[PATCH 00/19] qemu: migrate block bitmaps when migrating storage

When we are copying storage we should also preserve the block dirty bitmaps. This series implements their migration. For standard migration with shared storage we let qemu flush the bitmaps to disk and reload them on destination. There is possibility to migrate them using the migration stream too but it's not implemented in this series. Note that the first patch depends on the following qemu patches: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg03659.html We can now also formulate the condition for enabling incremental backup feature, but it still depends on stabilization of 'blockdev-reopen'. Peter Krempa (19): qemucapabilitiesdata: Update test data for qemu-6.0 on x86_64 qemu: capabilities: Introduce QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING qemu: Probe whether an image is 'qcow2 v2' from query-named-block-nodes virDomainMigrateVersion3Full: Don't set 'cancelled' to the same value qemuMigrationSrcPerformPeer2Peer3: Don't leak 'dom_xml' on cleanup testutils: virTestRewrapFile: Rewrap also '.argv' files storagevolxml2argvdata: Rewrap all output files storage: Format qcow2v3 volumes by default qemu: monitor: Introduce qemuMonitorBitmapRemove qemu: blockjob: Use qemuMonitorBitmapRemove for single bitmap removal qemu: migration_params: Add infrastructure for 'dirty-bitmaps' migration feature qemu: migration_cookie: Add XML handling for setting up bitmap migration qemu: migration_cookie: Add helpers for transforming the cookie into migration params qemu: domain: Store list of temporary bitmaps for migration in status XML tests: qemustatusxml2xml: Add status XML from migration with bitmaps tests: qemumigrationcookie: Add testing for block dirty bitmap migration qemu: migration: Clean up temporary bitmaps when cancelling a migration qemu: migration: Migrate block dirty bitmaps corresponding to checkpoints qemu: capabilities: Enable QEMU_CAPS_INCREMENTAL_BACKUP src/libvirt-domain.c | 2 - src/qemu/qemu_blockjob.c | 24 +- src/qemu/qemu_capabilities.c | 8 +- src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_domain.c | 90 ++- src/qemu/qemu_domain.h | 15 + src/qemu/qemu_migration.c | 366 ++++++++++- src/qemu/qemu_migration_cookie.c | 249 ++++++++ src/qemu/qemu_migration_cookie.h | 41 ++ src/qemu/qemu_migration_params.c | 24 + src/qemu/qemu_migration_params.h | 5 + src/qemu/qemu_monitor.c | 13 + src/qemu/qemu_monitor.h | 8 + src/qemu/qemu_monitor_json.c | 35 ++ src/qemu/qemu_monitor_json.h | 6 + src/storage/storage_util.c | 2 +- tests/meson.build | 2 +- tests/qemublocktest.c | 2 + tests/qemublocktestdata/bitmap/synthetic.json | 2 +- tests/qemublocktestdata/bitmap/synthetic.out | 1 + .../caps_6.0.0.x86_64.replies | 510 +++++++++------- .../caps_6.0.0.x86_64.xml | 16 +- .../nbd-bitmaps-xml2xml-in.xml | 52 ++ .../nbd-bitmaps-xml2xml-migparams.json | 25 + .../nbd-bitmaps-xml2xml-out.xml | 51 ++ tests/qemumigrationcookiexmltest.c | 166 ++++- tests/qemumonitorjsontest.c | 2 + .../migration-out-nbd-bitmaps-in.xml | 574 ++++++++++++++++++ .../migration-out-nbd-bitmaps-out.xml | 1 + tests/qemustatusxml2xmltest.c | 1 + tests/storagevolxml2argvdata/iso-input.argv | 6 +- tests/storagevolxml2argvdata/iso.argv | 4 +- .../logical-from-qcow2.argv | 6 +- tests/storagevolxml2argvdata/luks-cipher.argv | 8 +- .../luks-convert-encrypt.argv | 23 +- .../luks-convert-encrypt2fileqcow2.argv | 21 +- .../luks-convert-encrypt2fileraw.argv | 20 +- .../luks-convert-qcow2.argv | 21 +- .../storagevolxml2argvdata/luks-convert.argv | 20 +- tests/storagevolxml2argvdata/luks.argv | 8 +- tests/storagevolxml2argvdata/qcow2-1.1.argv | 8 +- .../storagevolxml2argvdata/qcow2-compat.argv | 8 +- .../qcow2-from-logical-compat.argv | 8 +- tests/storagevolxml2argvdata/qcow2-lazy.argv | 9 +- .../qcow2-luks-convert-encrypt.argv | 2 +- .../qcow2-luks-convert-encrypt2fileqcow2.argv | 2 +- tests/storagevolxml2argvdata/qcow2-luks.argv | 2 +- ...ow2-nobacking-convert-prealloc-compat.argv | 10 +- .../qcow2-nobacking-prealloc-compat.argv | 8 +- .../qcow2-nocapacity-convert-prealloc.argv | 9 +- .../qcow2-nocapacity.argv | 6 +- .../qcow2-nocow-compat.argv | 9 +- tests/storagevolxml2argvdata/qcow2-nocow.argv | 9 +- .../qcow2-zerocapacity.argv | 5 +- tests/testutils.c | 1 + 55 files changed, 2170 insertions(+), 357 deletions(-) create mode 100644 tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-in.xml create mode 100644 tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-migparams.json create mode 100644 tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-out.xml create mode 100644 tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml create mode 120000 tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-out.xml -- 2.29.2

Include the 'transform' member of 'block-bitmap-mapping'. Note that this is based on uncommited patches and will be updated once they are merged. --- .../caps_6.0.0.x86_64.replies | 510 ++++++++++-------- .../caps_6.0.0.x86_64.xml | 16 +- 2 files changed, 306 insertions(+), 220 deletions(-) diff --git a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.replies b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.replies index a1e3850b59..1af61272af 100644 --- a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.replies +++ b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.replies @@ -21,7 +21,7 @@ "minor": 2, "major": 5 }, - "package": "v5.2.0-1810-g2436651b26" + "package": "v5.2.0-1934-ge7bdfa1463" }, "id": "libvirt-2" } @@ -667,6 +667,10 @@ "name": "vhost-user-vsock-device", "parent": "vhost-vsock-common" }, + { + "name": "virtio-blk-pci-transitional", + "parent": "virtio-blk-pci-base" + }, { "name": "pcie-pci-bridge", "parent": "base-pci-bridge" @@ -708,8 +712,8 @@ "parent": "pci-device" }, { - "name": "sev-guest", - "parent": "confidential-guest-support" + "name": "chardev-stdio", + "parent": "chardev-fd" }, { "name": "usb-redir", @@ -732,8 +736,8 @@ "parent": "pci-vga" }, { - "name": "virtio-blk-pci-transitional", - "parent": "virtio-blk-pci-base" + "name": "kvm-pit", + "parent": "pit-common" }, { "name": "Haswell-v1-x86_64-cpu", @@ -756,8 +760,8 @@ "parent": "generic-pc-machine" }, { - "name": "kvm-pit", - "parent": "pit-common" + "name": "sev-guest", + "parent": "confidential-guest-support" }, { "name": "ich9-usb-uhci5", @@ -811,6 +815,10 @@ "name": "usb-hub", "parent": "usb-device" }, + { + "name": "chardev-serial", + "parent": "chardev-fd" + }, { "name": "virtio-blk-device", "parent": "virtio-device" @@ -852,8 +860,8 @@ "parent": "accel" }, { - "name": "chardev-serial", - "parent": "chardev-fd" + "name": "Cooperlake-x86_64-cpu", + "parent": "x86_64-cpu" }, { "name": "vhost-user-vsock-pci", @@ -891,14 +899,14 @@ "name": "memory-backend-ram", "parent": "memory-backend" }, - { - "name": "PCIE", - "parent": "PCI" - }, { "name": "e1000e", "parent": "pci-device" }, + { + "name": "PCIE", + "parent": "PCI" + }, { "name": "n270-x86_64-cpu", "parent": "x86_64-cpu" @@ -907,10 +915,6 @@ "name": "pxb-host", "parent": "pci-host-bridge" }, - { - "name": "Cooperlake-x86_64-cpu", - "parent": "x86_64-cpu" - }, { "name": "scsi-disk", "parent": "scsi-disk-base" @@ -979,14 +983,14 @@ "name": "pci-ipmi-kcs", "parent": "pci-device" }, - { - "name": "intel-iommu-iommu-memory-region", - "parent": "qemu:iommu-memory-region" - }, { "name": "xio3130-downstream", "parent": "pcie-slot" }, + { + "name": "intel-iommu-iommu-memory-region", + "parent": "qemu:iommu-memory-region" + }, { "name": "vhost-user-vsock-pci-non-transitional", "parent": "vhost-user-vsock-pci-base" @@ -995,14 +999,14 @@ "name": "pc-i440fx-2.3-machine", "parent": "generic-pc-machine" }, - { - "name": "PCI", - "parent": "bus" - }, { "name": "microvm-machine", "parent": "x86-machine" }, + { + "name": "PCI", + "parent": "bus" + }, { "name": "sdhci-bus", "parent": "sd-bus" @@ -1104,8 +1108,8 @@ "parent": "pci-device" }, { - "name": "virtio-input-host-pci", - "parent": "virtio-input-host-pci-base-type" + "name": "virtio-9p-pci-transitional", + "parent": "virtio-9p-pci-base" }, { "name": "nvdimm", @@ -1116,8 +1120,8 @@ "parent": "generic-pc-machine" }, { - "name": "virtio-9p-pci-transitional", - "parent": "virtio-9p-pci-base" + "name": "virtio-input-host-pci", + "parent": "virtio-input-host-pci-base-type" }, { "name": "Opteron_G1-x86_64-cpu", @@ -1143,6 +1147,10 @@ "name": "i82557c", "parent": "pci-device" }, + { + "name": "i82557b", + "parent": "pci-device" + }, { "name": "virtio-scsi-device", "parent": "virtio-scsi-common" @@ -1151,10 +1159,6 @@ "name": "pxb-pcie", "parent": "pci-device" }, - { - "name": "i82557b", - "parent": "pci-device" - }, { "name": "Haswell-IBRS-x86_64-cpu", "parent": "x86_64-cpu" @@ -1172,12 +1176,8 @@ "parent": "sys-bus-device" }, { - "name": "chardev-memory", - "parent": "chardev-ringbuf" - }, - { - "name": "pc-q35-2.8-machine", - "parent": "generic-pc-machine" + "name": "i82557a", + "parent": "pci-device" }, { "name": "vhost-user-scsi-pci-non-transitional", @@ -1188,12 +1188,16 @@ "parent": "isa-device" }, { - "name": "generic-sdhci", - "parent": "sys-bus-device" + "name": "chardev-udp", + "parent": "chardev" }, { - "name": "i82557a", - "parent": "pci-device" + "name": "pc-q35-2.8-machine", + "parent": "generic-pc-machine" + }, + { + "name": "generic-sdhci", + "parent": "sys-bus-device" }, { "name": "virtio-scsi-pci-non-transitional", @@ -1212,8 +1216,8 @@ "parent": "x86_64-cpu" }, { - "name": "chardev-udp", - "parent": "chardev" + "name": "chardev-memory", + "parent": "chardev-ringbuf" }, { "name": "EPYC-Rome-v1-x86_64-cpu", @@ -1263,14 +1267,14 @@ "name": "virtio-9p-pci-non-transitional", "parent": "virtio-9p-pci-base" }, - { - "name": "Nehalem-v2-x86_64-cpu", - "parent": "x86_64-cpu" - }, { "name": "memory-backend-file", "parent": "memory-backend" }, + { + "name": "Nehalem-v2-x86_64-cpu", + "parent": "x86_64-cpu" + }, { "name": "vhost-vsock-device", "parent": "vhost-vsock-common" @@ -1331,10 +1335,6 @@ "name": "tcg-accel", "parent": "accel" }, - { - "name": "piix4-ide", - "parent": "pci-ide" - }, { "name": "virtio-balloon-pci", "parent": "virtio-balloon-pci-base" @@ -1367,6 +1367,10 @@ "name": "ES1370", "parent": "pci-device" }, + { + "name": "pc-i440fx-2.6-machine", + "parent": "generic-pc-machine" + }, { "name": "i82551", "parent": "pci-device" @@ -1384,8 +1388,8 @@ "parent": "x86_64-cpu" }, { - "name": "pc-i440fx-2.6-machine", - "parent": "generic-pc-machine" + "name": "piix4-ide", + "parent": "pci-ide" }, { "name": "SandyBridge-x86_64-cpu", @@ -1427,14 +1431,14 @@ "name": "kvm-apic", "parent": "apic-common" }, - { - "name": "isa-pit", - "parent": "pit-common" - }, { "name": "kvm64-x86_64-cpu", "parent": "x86_64-cpu" }, + { + "name": "isa-pit", + "parent": "pit-common" + }, { "name": "Broadwell-v4-x86_64-cpu", "parent": "x86_64-cpu" @@ -1499,14 +1503,6 @@ "name": "core2duo-v1-x86_64-cpu", "parent": "x86_64-cpu" }, - { - "name": "vhost-user-blk-pci-non-transitional", - "parent": "vhost-user-blk-pci-base" - }, - { - "name": "virtio-rng-pci-non-transitional", - "parent": "virtio-rng-pci-base" - }, { "name": "cirrus-vga", "parent": "pci-device" @@ -1523,13 +1519,17 @@ "name": "pc-i440fx-2.1-machine", "parent": "generic-pc-machine" }, + { + "name": "virtio-serial-pci", + "parent": "virtio-serial-pci-base" + }, { "name": "i82559er", "parent": "pci-device" }, { - "name": "virtio-serial-pci", - "parent": "virtio-serial-pci-base" + "name": "virtio-rng-pci-non-transitional", + "parent": "virtio-rng-pci-base" }, { "name": "Skylake-Client-x86_64-cpu", @@ -1539,13 +1539,17 @@ "name": "Opteron_G3-x86_64-cpu", "parent": "x86_64-cpu" }, + { + "name": "container", + "parent": "object" + }, { "name": "isa-ide", "parent": "isa-device" }, { - "name": "container", - "parent": "object" + "name": "486-v1-x86_64-cpu", + "parent": "x86_64-cpu" }, { "name": "EPYC-v3-x86_64-cpu", @@ -1556,12 +1560,12 @@ "parent": "scsi-disk-base" }, { - "name": "gpex-root", - "parent": "pci-device" + "name": "vhost-user-blk-pci-non-transitional", + "parent": "vhost-user-blk-pci-base" }, { - "name": "486-v1-x86_64-cpu", - "parent": "x86_64-cpu" + "name": "gpex-root", + "parent": "pci-device" }, { "name": "vmport", @@ -1587,14 +1591,14 @@ "name": "e1000-82545em", "parent": "e1000-base" }, - { - "name": "sdhci-pci", - "parent": "pci-device" - }, { "name": "pxb-pcie-bus", "parent": "PCIE" }, + { + "name": "sdhci-pci", + "parent": "pci-device" + }, { "name": "vhost-user-scsi", "parent": "vhost-scsi-common" @@ -1768,11 +1772,11 @@ "parent": "base-sysbus-fdc" }, { - "name": "i82559c", + "name": "AMDVI-PCI", "parent": "pci-device" }, { - "name": "AMDVI-PCI", + "name": "i82559c", "parent": "pci-device" }, { @@ -1820,11 +1824,11 @@ "parent": "vhost-user-scsi-pci-base" }, { - "name": "i82559a", + "name": "kvaser_pci", "parent": "pci-device" }, { - "name": "kvaser_pci", + "name": "i82559a", "parent": "pci-device" }, { @@ -1932,16 +1936,16 @@ "parent": "virtio-iommu-device-base" }, { - "name": "chardev-braille", - "parent": "chardev" + "name": "vmcoreinfo", + "parent": "device" }, { "name": "Icelake-Client-v1-x86_64-cpu", "parent": "x86_64-cpu" }, { - "name": "vmcoreinfo", - "parent": "device" + "name": "chardev-braille", + "parent": "chardev" }, { "name": "tpci200", @@ -1963,10 +1967,6 @@ "name": "qio-channel-socket", "parent": "qio-channel" }, - { - "name": "chardev-socket", - "parent": "chardev" - }, { "name": "coreduo-v1-x86_64-cpu", "parent": "x86_64-cpu" @@ -1984,17 +1984,13 @@ "parent": "object" }, { - "name": "hyperv-testdev", - "parent": "isa-device" + "name": "chardev-socket", + "parent": "chardev" }, { "name": "clock", "parent": "object" }, - { - "name": "virtio-net-device", - "parent": "virtio-device" - }, { "name": "Haswell-v2-x86_64-cpu", "parent": "x86_64-cpu" @@ -2003,6 +1999,10 @@ "name": "host-x86_64-cpu", "parent": "max-x86_64-cpu" }, + { + "name": "secret", + "parent": "secret_common" + }, { "name": "usb-ehci", "parent": "pci-ehci-usb" @@ -2048,8 +2048,8 @@ "parent": "scsi-disk-base" }, { - "name": "secret", - "parent": "secret_common" + "name": "Cascadelake-Server-noTSX-x86_64-cpu", + "parent": "x86_64-cpu" }, { "name": "usb-kbd", @@ -2064,16 +2064,16 @@ "parent": "device" }, { - "name": "usb-mtp", - "parent": "usb-device" + "name": "virtio-net-device", + "parent": "virtio-device" }, { "name": "filter-replay", "parent": "netfilter" }, { - "name": "Cascadelake-Server-noTSX-x86_64-cpu", - "parent": "x86_64-cpu" + "name": "usb-mtp", + "parent": "usb-device" }, { "name": "input-linux", @@ -2088,8 +2088,12 @@ "parent": "x86_64-cpu" }, { - "name": "pc-q35-5.1-machine", - "parent": "generic-pc-machine" + "name": "lsi53c810", + "parent": "lsi53c895a" + }, + { + "name": "hyperv-testdev", + "parent": "isa-device" }, { "name": "s3c-sdhci", @@ -2112,8 +2116,8 @@ "parent": "ccid-card" }, { - "name": "virtconsole", - "parent": "virtserialport" + "name": "pc-q35-5.1-machine", + "parent": "generic-pc-machine" }, { "name": "pc-i440fx-1.7-machine", @@ -2124,21 +2128,21 @@ "parent": "virtio-input-hid-device" }, { - "name": "lsi53c810", - "parent": "lsi53c895a" + "name": "virtconsole", + "parent": "virtserialport" }, { "name": "ioh3420", "parent": "pcie-root-port-base" }, - { - "name": "filter-mirror", - "parent": "netfilter" - }, { "name": "Skylake-Client-v1-x86_64-cpu", "parent": "x86_64-cpu" }, + { + "name": "filter-mirror", + "parent": "netfilter" + }, { "name": "throttle-group", "parent": "object" @@ -2235,14 +2239,14 @@ "name": "pc-dimm", "parent": "device" }, - { - "name": "virtio-net-pci-transitional", - "parent": "virtio-net-pci-base" - }, { "name": "virtio-balloon-pci-non-transitional", "parent": "virtio-balloon-pci-base" }, + { + "name": "virtio-net-pci-transitional", + "parent": "virtio-net-pci-base" + }, { "name": "ipmi-bmc-sim", "parent": "ipmi-bmc" @@ -2303,14 +2307,14 @@ "name": "pxb-bus", "parent": "PCI" }, - { - "name": "virtio-mmio", - "parent": "sys-bus-device" - }, { "name": "pentium2-x86_64-cpu", "parent": "x86_64-cpu" }, + { + "name": "virtio-mmio", + "parent": "sys-bus-device" + }, { "name": "Broadwell-v1-x86_64-cpu", "parent": "x86_64-cpu" @@ -2567,14 +2571,14 @@ "name": "cfi.pflash01", "parent": "sys-bus-device" }, - { - "name": "Skylake-Server-x86_64-cpu", - "parent": "x86_64-cpu" - }, { "name": "pc-q35-2.7-machine", "parent": "generic-pc-machine" }, + { + "name": "Skylake-Server-x86_64-cpu", + "parent": "x86_64-cpu" + }, { "name": "isa-parallel", "parent": "isa-device" @@ -2796,8 +2800,8 @@ "parent": "x86_64-cpu" }, { - "name": "kvm64-v1-x86_64-cpu", - "parent": "x86_64-cpu" + "name": "pcie-root-port", + "parent": "pcie-root-port-base" }, { "name": "IDE", @@ -2808,8 +2812,8 @@ "parent": "x86_64-cpu" }, { - "name": "pcie-root-port", - "parent": "pcie-root-port-base" + "name": "kvm64-v1-x86_64-cpu", + "parent": "x86_64-cpu" }, { "name": "mptsas1068", @@ -2907,10 +2911,6 @@ "name": "qio-channel-tls", "parent": "qio-channel" }, - { - "name": "chardev-stdio", - "parent": "chardev-fd" - }, { "name": "virtio-vga", "parent": "virtio-vga-base-type" @@ -7314,6 +7314,10 @@ "name": "xsaves", "type": "bool" }, + { + "name": "vgif", + "type": "bool" + }, { "name": "mce", "type": "bool" @@ -7443,6 +7447,10 @@ "name": "tcg-cpuid", "type": "bool" }, + { + "name": "vmx-entry-load-pkrs", + "type": "bool" + }, { "name": "x-hv-max-vps", "type": "int32" @@ -7700,6 +7708,10 @@ "name": "kvm-pv-tlb-flush", "type": "bool" }, + { + "name": "vmx-rdtsc-exit", + "type": "bool" + }, { "name": "vmx-cr8-load-exit", "type": "bool" @@ -7713,7 +7725,11 @@ "type": "bool" }, { - "name": "vmx-rdtsc-exit", + "name": "svme-addr-chk", + "type": "bool" + }, + { + "name": "vmx-exit-load-pkrs", "type": "bool" }, { @@ -7855,6 +7871,14 @@ "description": "on/off", "type": "bool" }, + { + "name": "avic", + "type": "bool" + }, + { + "name": "ds", + "type": "bool" + }, { "name": "legacy-cache", "type": "bool" @@ -7873,11 +7897,11 @@ "type": "bool" }, { - "name": "ds", + "name": "osvw", "type": "bool" }, { - "name": "osvw", + "name": "pks", "type": "bool" }, { @@ -7904,6 +7928,10 @@ "name": "vmx-cr8-store-exit", "type": "bool" }, + { + "name": "vmx-ept-1gb", + "type": "bool" + }, { "name": "nrip-save", "type": "bool" @@ -7917,7 +7945,7 @@ "type": "bool" }, { - "name": "lmce", + "name": "vmx-ept-2mb", "type": "bool" }, { @@ -7937,7 +7965,7 @@ "type": "bool" }, { - "name": "sse2", + "name": "lmce", "type": "bool" }, { @@ -7965,15 +7993,15 @@ "type": "bool" }, { - "name": "vmx-ept-1gb", + "name": "avx", "type": "bool" }, { - "name": "avx", + "name": "topoext", "type": "bool" }, { - "name": "topoext", + "name": "sse2", "type": "bool" }, { @@ -8171,7 +8199,7 @@ "type": "bool" }, { - "name": "vmx-ept-2mb", + "name": "vmx-page-walk-4", "type": "bool" }, { @@ -8239,7 +8267,7 @@ "type": "bool" }, { - "name": "vmx-page-walk-4", + "name": "v-vmsave-vmload", "type": "bool" }, { @@ -10857,6 +10885,11 @@ ], "option": "iscsi" }, + { + "parameters": [ + ], + "option": "acpi" + }, { "parameters": [ { @@ -10986,6 +11019,31 @@ ], "option": "spice" }, + { + "parameters": [ + { + "name": "resourcecontrol", + "type": "string" + }, + { + "name": "spawn", + "type": "string" + }, + { + "name": "elevateprivileges", + "type": "string" + }, + { + "name": "obsolete", + "type": "string" + }, + { + "name": "enable", + "type": "boolean" + } + ], + "option": "sandbox" + }, { "parameters": [ { @@ -11175,31 +11233,6 @@ ], "option": "fsdev" }, - { - "parameters": [ - { - "name": "resourcecontrol", - "type": "string" - }, - { - "name": "spawn", - "type": "string" - }, - { - "name": "elevateprivileges", - "type": "string" - }, - { - "name": "obsolete", - "type": "string" - }, - { - "name": "enable", - "type": "boolean" - } - ], - "option": "sandbox" - }, { "parameters": [ ], @@ -11298,11 +11331,6 @@ ], "option": "vnc" }, - { - "parameters": [ - ], - "option": "acpi" - }, { "parameters": [ { @@ -25357,6 +25385,11 @@ { "name": "alias", "type": "str" + }, + { + "name": "transform", + "default": null, + "type": "568" } ], "meta-type": "object" @@ -25384,7 +25417,7 @@ "members": [ { "name": "data", - "type": "568" + "type": "569" } ], "meta-type": "object" @@ -25760,7 +25793,7 @@ "members": [ { "name": "bus", - "type": "569" + "type": "570" }, { "name": "devices", @@ -25832,7 +25865,7 @@ "members": [ { "name": "data", - "type": "570" + "type": "571" } ], "meta-type": "object" @@ -25842,7 +25875,7 @@ "members": [ { "name": "data", - "type": "571" + "type": "572" } ], "meta-type": "object" @@ -25852,7 +25885,7 @@ "members": [ { "name": "data", - "type": "572" + "type": "573" } ], "meta-type": "object" @@ -26047,7 +26080,7 @@ "members": [ { "name": "type", - "type": "573" + "type": "574" }, { "name": "hash", @@ -26126,13 +26159,13 @@ }, { "case": "luks", - "type": "575" + "type": "576" } ], "members": [ { "name": "format", - "type": "574" + "type": "575" } ], "meta-type": "object" @@ -26158,17 +26191,17 @@ "variants": [ { "case": "full", - "type": "577" + "type": "578" }, { "case": "erasure-coded", - "type": "578" + "type": "579" } ], "members": [ { "name": "type", - "type": "576" + "type": "577" } ], "meta-type": "object" @@ -26224,7 +26257,7 @@ "variants": [ { "case": "luks", - "type": "579" + "type": "580" }, { "case": "qcow", @@ -26234,7 +26267,7 @@ "members": [ { "name": "format", - "type": "574" + "type": "575" } ], "meta-type": "object" @@ -26732,7 +26765,7 @@ "members": [ { "name": "button", - "type": "580" + "type": "581" }, { "name": "down", @@ -26746,7 +26779,7 @@ "members": [ { "name": "axis", - "type": "581" + "type": "582" }, { "name": "value", @@ -26758,11 +26791,22 @@ { "name": "568", "members": [ + { + "name": "persistent", + "default": null, + "type": "bool" + } ], "meta-type": "object" }, { "name": "569", + "members": [ + ], + "meta-type": "object" + }, + { + "name": "570", "members": [ { "name": "number", @@ -26778,21 +26822,21 @@ }, { "name": "io_range", - "type": "582" + "type": "583" }, { "name": "memory_range", - "type": "582" + "type": "583" }, { "name": "prefetchable_range", - "type": "582" + "type": "583" } ], "meta-type": "object" }, { - "name": "570", + "name": "571", "members": [ { "name": "compat", @@ -26830,12 +26874,12 @@ { "name": "encrypt", "default": null, - "type": "583" + "type": "584" }, { "name": "bitmaps", "default": null, - "type": "[584]" + "type": "[585]" }, { "name": "compression-type", @@ -26845,7 +26889,7 @@ "meta-type": "object" }, { - "name": "571", + "name": "572", "members": [ { "name": "create-type", @@ -26867,7 +26911,7 @@ "meta-type": "object" }, { - "name": "572", + "name": "573", "members": [ { "name": "cipher-alg", @@ -26904,13 +26948,13 @@ }, { "name": "slots", - "type": "[585]" + "type": "[586]" } ], "meta-type": "object" }, { - "name": "573", + "name": "574", "meta-type": "enum", "values": [ "md5", @@ -26918,7 +26962,7 @@ ] }, { - "name": "574", + "name": "575", "meta-type": "enum", "values": [ "qcow", @@ -26926,7 +26970,7 @@ ] }, { - "name": "575", + "name": "576", "members": [ { "name": "key-secret", @@ -26967,7 +27011,7 @@ "meta-type": "object" }, { - "name": "576", + "name": "577", "meta-type": "enum", "values": [ "full", @@ -26975,7 +27019,7 @@ ] }, { - "name": "577", + "name": "578", "members": [ { "name": "copies", @@ -26985,7 +27029,7 @@ "meta-type": "object" }, { - "name": "578", + "name": "579", "members": [ { "name": "data-strips", @@ -26999,7 +27043,7 @@ "meta-type": "object" }, { - "name": "579", + "name": "580", "members": [ { "name": "state", @@ -27034,7 +27078,7 @@ "meta-type": "object" }, { - "name": "580", + "name": "581", "meta-type": "enum", "values": [ "left", @@ -27047,7 +27091,7 @@ ] }, { - "name": "581", + "name": "582", "meta-type": "enum", "values": [ "x", @@ -27055,7 +27099,7 @@ ] }, { - "name": "582", + "name": "583", "members": [ { "name": "base", @@ -27069,12 +27113,12 @@ "meta-type": "object" }, { - "name": "583", + "name": "584", "tag": "format", "variants": [ { "case": "luks", - "type": "572" + "type": "573" }, { "case": "aes", @@ -27090,12 +27134,12 @@ "meta-type": "object" }, { - "name": "[584]", - "element-type": "584", + "name": "[585]", + "element-type": "585", "meta-type": "array" }, { - "name": "584", + "name": "585", "members": [ { "name": "name", @@ -27107,7 +27151,7 @@ }, { "name": "flags", - "type": "[586]" + "type": "[587]" } ], "meta-type": "object" @@ -27118,12 +27162,12 @@ "meta-type": "array" }, { - "name": "[585]", - "element-type": "585", + "name": "[586]", + "element-type": "586", "meta-type": "array" }, { - "name": "585", + "name": "586", "members": [ { "name": "active", @@ -27147,12 +27191,12 @@ "meta-type": "object" }, { - "name": "[586]", - "element-type": "586", + "name": "[587]", + "element-type": "587", "meta-type": "array" }, { - "name": "586", + "name": "587", "meta-type": "enum", "values": [ "in-use", @@ -27193,6 +27237,7 @@ "name": "base", "props": { "vmx-entry-load-rtit-ctl": false, + "svme-addr-chk": false, "cmov": true, "ia64": false, "ssb-no": false, @@ -27277,6 +27322,7 @@ "vmx-unrestricted-guest": false, "vmx-cr3-store-noexit": false, "pku": false, + "pks": false, "smx": false, "cmp-legacy": true, "avx512-4fmaps": false, @@ -27392,6 +27438,7 @@ "kvmclock": true, "vmx-zero-len-inject": false, "pschange-mc-no": true, + "v-vmsave-vmload": false, "vmx-rdrand-exit": false, "lwp": false, "amd-ssbd": true, @@ -27429,6 +27476,7 @@ "vmx-movdr-exit": false, "pse": true, "avx2": true, + "avic": false, "sep": true, "virt-ssbd": true, "vmx-cr3-load-noexit": false, @@ -27445,6 +27493,7 @@ "amd-stibp": true, "vmx-preemption-timer": false, "clflushopt": true, + "vmx-entry-load-pkrs": false, "vmx-vnmi-pending": false, "monitor": false, "vmx-vintr-pending": false, @@ -27454,6 +27503,7 @@ "pcid": false, "taa-no": false, "arch-capabilities": true, + "vgif": false, "vmx-secondary-ctls": false, "vmx-xsaves": false, "clzero": true, @@ -27488,6 +27538,7 @@ "vmx-entry-load-efer": false, "model-id": "AMD Ryzen 9 3900X 12-Core Processor ", "sha-ni": true, + "vmx-exit-load-pkrs": false, "abm": true, "vmx-ept-advanced-exitinfo": false, "avx512pf": false, @@ -27519,6 +27570,7 @@ "name": "base", "props": { "vmx-entry-load-rtit-ctl": false, + "svme-addr-chk": false, "cmov": true, "ia64": false, "ssb-no": false, @@ -27603,6 +27655,7 @@ "vmx-unrestricted-guest": false, "vmx-cr3-store-noexit": false, "pku": false, + "pks": false, "smx": false, "cmp-legacy": true, "avx512-4fmaps": false, @@ -27718,6 +27771,7 @@ "kvmclock": true, "vmx-zero-len-inject": false, "pschange-mc-no": true, + "v-vmsave-vmload": false, "vmx-rdrand-exit": false, "lwp": false, "amd-ssbd": true, @@ -27755,6 +27809,7 @@ "vmx-movdr-exit": false, "pse": true, "avx2": true, + "avic": false, "sep": true, "virt-ssbd": true, "vmx-cr3-load-noexit": false, @@ -27771,6 +27826,7 @@ "amd-stibp": true, "vmx-preemption-timer": false, "clflushopt": true, + "vmx-entry-load-pkrs": false, "vmx-vnmi-pending": false, "monitor": false, "vmx-vintr-pending": false, @@ -27780,6 +27836,7 @@ "pcid": false, "taa-no": false, "arch-capabilities": true, + "vgif": false, "vmx-secondary-ctls": false, "vmx-xsaves": false, "clzero": true, @@ -27814,6 +27871,7 @@ "vmx-entry-load-efer": false, "model-id": "AMD Ryzen 9 3900X 12-Core Processor ", "sha-ni": true, + "vmx-exit-load-pkrs": false, "abm": true, "vmx-ept-advanced-exitinfo": false, "avx512pf": false, @@ -30208,6 +30266,7 @@ "name": "base", "props": { "vmx-entry-load-rtit-ctl": false, + "svme-addr-chk": false, "cmov": true, "ia64": false, "ssb-no": false, @@ -30292,6 +30351,7 @@ "vmx-unrestricted-guest": false, "vmx-cr3-store-noexit": false, "pku": true, + "pks": true, "smx": false, "cmp-legacy": false, "avx512-4fmaps": false, @@ -30407,6 +30467,7 @@ "kvmclock": false, "vmx-zero-len-inject": false, "pschange-mc-no": false, + "v-vmsave-vmload": false, "vmx-rdrand-exit": false, "lwp": false, "amd-ssbd": false, @@ -30444,6 +30505,7 @@ "vmx-movdr-exit": false, "pse": true, "avx2": false, + "avic": false, "sep": true, "virt-ssbd": false, "vmx-cr3-load-noexit": false, @@ -30460,6 +30522,7 @@ "amd-stibp": false, "vmx-preemption-timer": false, "clflushopt": true, + "vmx-entry-load-pkrs": false, "vmx-vnmi-pending": false, "monitor": true, "vmx-vintr-pending": false, @@ -30469,6 +30532,7 @@ "pcid": false, "taa-no": false, "arch-capabilities": false, + "vgif": false, "vmx-secondary-ctls": false, "vmx-xsaves": false, "clzero": false, @@ -30503,6 +30567,7 @@ "vmx-entry-load-efer": false, "model-id": "QEMU TCG CPU version 2.5+", "sha-ni": false, + "vmx-exit-load-pkrs": false, "abm": true, "vmx-ept-advanced-exitinfo": false, "avx512pf": false, @@ -30534,6 +30599,7 @@ "name": "base", "props": { "vmx-entry-load-rtit-ctl": false, + "svme-addr-chk": false, "cmov": true, "ia64": false, "ssb-no": false, @@ -30618,6 +30684,7 @@ "vmx-unrestricted-guest": false, "vmx-cr3-store-noexit": false, "pku": true, + "pks": true, "smx": false, "cmp-legacy": false, "avx512-4fmaps": false, @@ -30733,6 +30800,7 @@ "kvmclock": false, "vmx-zero-len-inject": false, "pschange-mc-no": false, + "v-vmsave-vmload": false, "vmx-rdrand-exit": false, "lwp": false, "amd-ssbd": false, @@ -30770,6 +30838,7 @@ "vmx-movdr-exit": false, "pse": true, "avx2": false, + "avic": false, "sep": true, "virt-ssbd": false, "vmx-cr3-load-noexit": false, @@ -30786,6 +30855,7 @@ "amd-stibp": false, "vmx-preemption-timer": false, "clflushopt": true, + "vmx-entry-load-pkrs": false, "vmx-vnmi-pending": false, "monitor": true, "vmx-vintr-pending": false, @@ -30795,6 +30865,7 @@ "pcid": false, "taa-no": false, "arch-capabilities": false, + "vgif": false, "vmx-secondary-ctls": false, "vmx-xsaves": false, "clzero": false, @@ -30829,6 +30900,7 @@ "vmx-entry-load-efer": false, "model-id": "QEMU TCG CPU version 2.5+", "sha-ni": false, + "vmx-exit-load-pkrs": false, "abm": true, "vmx-ept-advanced-exitinfo": false, "avx512pf": false, diff --git a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml index ddfa701798..f2ec32e46b 100644 --- a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml @@ -258,10 +258,11 @@ <version>5002050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100242</microcodeVersion> - <package>v5.2.0-1810-g2436651b26</package> + <package>v5.2.0-1934-ge7bdfa1463</package> <arch>x86_64</arch> <hostCPU type='kvm' model='base' migratability='yes'> <property name='vmx-entry-load-rtit-ctl' type='boolean' value='false'/> + <property name='svme-addr-chk' type='boolean' value='false'/> <property name='cmov' type='boolean' value='true' migratable='yes'/> <property name='ia64' type='boolean' value='false'/> <property name='ssb-no' type='boolean' value='false'/> @@ -346,6 +347,7 @@ <property name='vmx-unrestricted-guest' type='boolean' value='false'/> <property name='vmx-cr3-store-noexit' type='boolean' value='false'/> <property name='pku' type='boolean' value='false'/> + <property name='pks' type='boolean' value='false'/> <property name='smx' type='boolean' value='false'/> <property name='cmp-legacy' type='boolean' value='true' migratable='yes'/> <property name='avx512-4fmaps' type='boolean' value='false'/> @@ -461,6 +463,7 @@ <property name='kvmclock' type='boolean' value='true' migratable='yes'/> <property name='vmx-zero-len-inject' type='boolean' value='false'/> <property name='pschange-mc-no' type='boolean' value='true' migratable='yes'/> + <property name='v-vmsave-vmload' type='boolean' value='false'/> <property name='vmx-rdrand-exit' type='boolean' value='false'/> <property name='lwp' type='boolean' value='false'/> <property name='amd-ssbd' type='boolean' value='true' migratable='yes'/> @@ -498,6 +501,7 @@ <property name='vmx-movdr-exit' type='boolean' value='false'/> <property name='pse' type='boolean' value='true' migratable='yes'/> <property name='avx2' type='boolean' value='true' migratable='yes'/> + <property name='avic' type='boolean' value='false'/> <property name='sep' type='boolean' value='true' migratable='yes'/> <property name='virt-ssbd' type='boolean' value='true' migratable='yes'/> <property name='vmx-cr3-load-noexit' type='boolean' value='false'/> @@ -514,6 +518,7 @@ <property name='amd-stibp' type='boolean' value='true' migratable='yes'/> <property name='vmx-preemption-timer' type='boolean' value='false'/> <property name='clflushopt' type='boolean' value='true' migratable='yes'/> + <property name='vmx-entry-load-pkrs' type='boolean' value='false'/> <property name='vmx-vnmi-pending' type='boolean' value='false'/> <property name='monitor' type='boolean' value='false'/> <property name='vmx-vintr-pending' type='boolean' value='false'/> @@ -523,6 +528,7 @@ <property name='pcid' type='boolean' value='false'/> <property name='taa-no' type='boolean' value='false'/> <property name='arch-capabilities' type='boolean' value='true' migratable='yes'/> + <property name='vgif' type='boolean' value='false'/> <property name='vmx-secondary-ctls' type='boolean' value='false'/> <property name='vmx-xsaves' type='boolean' value='false'/> <property name='clzero' type='boolean' value='true' migratable='yes'/> @@ -557,6 +563,7 @@ <property name='vmx-entry-load-efer' type='boolean' value='false'/> <property name='model-id' type='string' value='AMD Ryzen 9 3900X 12-Core Processor '/> <property name='sha-ni' type='boolean' value='true' migratable='yes'/> + <property name='vmx-exit-load-pkrs' type='boolean' value='false'/> <property name='abm' type='boolean' value='true' migratable='yes'/> <property name='vmx-ept-advanced-exitinfo' type='boolean' value='false'/> <property name='avx512pf' type='boolean' value='false'/> @@ -1470,6 +1477,7 @@ <machine type='kvm' name='pc-q35-2.11' hotplugCpus='yes' maxCpus='288' defaultCPU='qemu64-x86_64-cpu' numaMemSupported='yes' defaultRAMid='pc.ram'/> <hostCPU type='tcg' model='base' migratability='yes'> <property name='vmx-entry-load-rtit-ctl' type='boolean' value='false'/> + <property name='svme-addr-chk' type='boolean' value='false'/> <property name='cmov' type='boolean' value='true' migratable='yes'/> <property name='ia64' type='boolean' value='false'/> <property name='ssb-no' type='boolean' value='false'/> @@ -1554,6 +1562,7 @@ <property name='vmx-unrestricted-guest' type='boolean' value='false'/> <property name='vmx-cr3-store-noexit' type='boolean' value='false'/> <property name='pku' type='boolean' value='true' migratable='yes'/> + <property name='pks' type='boolean' value='true' migratable='yes'/> <property name='smx' type='boolean' value='false'/> <property name='cmp-legacy' type='boolean' value='false'/> <property name='avx512-4fmaps' type='boolean' value='false'/> @@ -1669,6 +1678,7 @@ <property name='kvmclock' type='boolean' value='false'/> <property name='vmx-zero-len-inject' type='boolean' value='false'/> <property name='pschange-mc-no' type='boolean' value='false'/> + <property name='v-vmsave-vmload' type='boolean' value='false'/> <property name='vmx-rdrand-exit' type='boolean' value='false'/> <property name='lwp' type='boolean' value='false'/> <property name='amd-ssbd' type='boolean' value='false'/> @@ -1706,6 +1716,7 @@ <property name='vmx-movdr-exit' type='boolean' value='false'/> <property name='pse' type='boolean' value='true' migratable='yes'/> <property name='avx2' type='boolean' value='false'/> + <property name='avic' type='boolean' value='false'/> <property name='sep' type='boolean' value='true' migratable='yes'/> <property name='virt-ssbd' type='boolean' value='false'/> <property name='vmx-cr3-load-noexit' type='boolean' value='false'/> @@ -1722,6 +1733,7 @@ <property name='amd-stibp' type='boolean' value='false'/> <property name='vmx-preemption-timer' type='boolean' value='false'/> <property name='clflushopt' type='boolean' value='true' migratable='yes'/> + <property name='vmx-entry-load-pkrs' type='boolean' value='false'/> <property name='vmx-vnmi-pending' type='boolean' value='false'/> <property name='monitor' type='boolean' value='true' migratable='yes'/> <property name='vmx-vintr-pending' type='boolean' value='false'/> @@ -1731,6 +1743,7 @@ <property name='pcid' type='boolean' value='false'/> <property name='taa-no' type='boolean' value='false'/> <property name='arch-capabilities' type='boolean' value='false'/> + <property name='vgif' type='boolean' value='false'/> <property name='vmx-secondary-ctls' type='boolean' value='false'/> <property name='vmx-xsaves' type='boolean' value='false'/> <property name='clzero' type='boolean' value='false'/> @@ -1765,6 +1778,7 @@ <property name='vmx-entry-load-efer' type='boolean' value='false'/> <property name='model-id' type='string' value='QEMU TCG CPU version 2.5+'/> <property name='sha-ni' type='boolean' value='false'/> + <property name='vmx-exit-load-pkrs' type='boolean' value='false'/> <property name='abm' type='boolean' value='true' migratable='yes'/> <property name='vmx-ept-advanced-exitinfo' type='boolean' value='false'/> <property name='avx512pf' type='boolean' value='false'/> -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:40 +0100, Peter Krempa wrote:
Include the 'transform' member of 'block-bitmap-mapping'.
Note that this is based on uncommited patches and will be updated once they are merged. --- .../caps_6.0.0.x86_64.replies | 510 ++++++++++-------- .../caps_6.0.0.x86_64.xml | 16 +- 2 files changed, 306 insertions(+), 220 deletions(-)
Looks ok, but obviously we need to wait for the QEMU patches to be merged first. Jirka

The capability represents qemu's ability to setup mappings for migrating block dirty bitmaps and is based on presence of the 'transform' property of the 'block-bitmap-mapping' property of 'migrate-set-parameters' QMP command. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ccf810ff96..38555dde98 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -616,6 +616,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "vhost-user-blk", "cpu-max", "memory-backend-file.x-use-canonical-path-for-ramblock-id", + "migration-param.block-bitmap-mapping", ); @@ -1549,6 +1550,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "migrate-set-parameters/arg-type/xbzrle-cache-size", QEMU_CAPS_MIGRATION_PARAM_XBZRLE_CACHE_SIZE }, { "set-numa-node/arg-type/+hmat-lb", QEMU_CAPS_NUMA_HMAT }, { "netdev_add/arg-type/+vhost-vdpa", QEMU_CAPS_NETDEV_VHOST_VDPA }, + { "migrate-set-parameters/arg-type/block-bitmap-mapping/transform", QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING }, }; typedef struct _virQEMUCapsObjectTypeProps virQEMUCapsObjectTypeProps; diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 6fd7922926..03d6ba60cf 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -596,6 +596,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_DEVICE_VHOST_USER_BLK, /* -device vhost-user-blk */ QEMU_CAPS_CPU_MAX, /* -cpu max */ QEMU_CAPS_X_USE_CANONICAL_PATH_FOR_RAMBLOCK_ID, /* -object memory-backend-file,x-use-canonical-path-for-ramblock-id= */ + QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING, /* block-bitmap-mapping in migrate-set-parameters */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:41 +0100, Peter Krempa wrote:
The capability represents qemu's ability to setup mappings for migrating block dirty bitmaps and is based on presence of the 'transform' property of the 'block-bitmap-mapping' property of 'migrate-set-parameters' QMP command.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + 2 files changed, 3 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ccf810ff96..38555dde98 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -616,6 +616,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "vhost-user-blk", "cpu-max", "memory-backend-file.x-use-canonical-path-for-ramblock-id", + "migration-param.block-bitmap-mapping", );
@@ -1549,6 +1550,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "migrate-set-parameters/arg-type/xbzrle-cache-size", QEMU_CAPS_MIGRATION_PARAM_XBZRLE_CACHE_SIZE }, { "set-numa-node/arg-type/+hmat-lb", QEMU_CAPS_NUMA_HMAT }, { "netdev_add/arg-type/+vhost-vdpa", QEMU_CAPS_NETDEV_VHOST_VDPA }, + { "migrate-set-parameters/arg-type/block-bitmap-mapping/transform", QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING }, };
So how is it possible this change is not reflected in tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml after the previous patch updated QEMU replies? Interestingly enough, tests pass after this patch so either the capability detection is not working or QEMU replies do not actually contain what you're looking for here. Jirka

On Fri, Feb 12, 2021 at 08:57:08 +0100, Jiri Denemark wrote:
On Thu, Feb 11, 2021 at 16:37:41 +0100, Peter Krempa wrote:
The capability represents qemu's ability to setup mappings for migrating block dirty bitmaps and is based on presence of the 'transform' property of the 'block-bitmap-mapping' property of 'migrate-set-parameters' QMP command.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + 2 files changed, 3 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ccf810ff96..38555dde98 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -616,6 +616,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "vhost-user-blk", "cpu-max", "memory-backend-file.x-use-canonical-path-for-ramblock-id", + "migration-param.block-bitmap-mapping", );
@@ -1549,6 +1550,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "migrate-set-parameters/arg-type/xbzrle-cache-size", QEMU_CAPS_MIGRATION_PARAM_XBZRLE_CACHE_SIZE }, { "set-numa-node/arg-type/+hmat-lb", QEMU_CAPS_NUMA_HMAT }, { "netdev_add/arg-type/+vhost-vdpa", QEMU_CAPS_NETDEV_VHOST_VDPA }, + { "migrate-set-parameters/arg-type/block-bitmap-mapping/transform", QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING }, };
So how is it possible this change is not reflected in tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml after the previous patch updated QEMU replies? Interestingly enough, tests pass after this patch so either the capability detection is not working or QEMU replies do not actually contain what you're looking for here.
Oops, there's a mistake in the query string where I've missed 'bitmaps' subcomponent. Well actually I've already noticed this before, but squashed the changes to a patch that I've ultimately removed from the series ... diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c7ab144a8e..0e0926d0e5 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -1550,7 +1550,8 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "migrate-set-parameters/arg-type/xbzrle-cache-size", QEMU_CAPS_MIGRATION_PARAM_XBZRLE_CACHE_SIZE }, { "set-numa-node/arg-type/+hmat-lb", QEMU_CAPS_NUMA_HMAT }, { "netdev_add/arg-type/+vhost-vdpa", QEMU_CAPS_NETDEV_VHOST_VDPA }, - { "migrate-set-parameters/arg-type/block-bitmap-mapping/transform", QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING }, + { "migrate-set-parameters/arg-type/block-bitmap-mapping/bitmaps/transform", + QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING }, }; typedef struct _virQEMUCapsObjectTypeProps virQEMUCapsObjectTypeProps; diff --git a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml index f2ec32e46b..b9a36cb71e 100644 --- a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml @@ -255,6 +255,7 @@ <flag name='vhost-user-blk'/> <flag name='cpu-max'/> <flag name='memory-backend-file.x-use-canonical-path-for-ramblock-id'/> + <flag name='migration-param.block-bitmap-mapping'/> <version>5002050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100242</microcodeVersion>

On Fri, Feb 12, 2021 at 09:30:25 +0100, Peter Krempa wrote:
On Fri, Feb 12, 2021 at 08:57:08 +0100, Jiri Denemark wrote:
On Thu, Feb 11, 2021 at 16:37:41 +0100, Peter Krempa wrote:
The capability represents qemu's ability to setup mappings for migrating block dirty bitmaps and is based on presence of the 'transform' property of the 'block-bitmap-mapping' property of 'migrate-set-parameters' QMP command.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + 2 files changed, 3 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index ccf810ff96..38555dde98 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -616,6 +616,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "vhost-user-blk", "cpu-max", "memory-backend-file.x-use-canonical-path-for-ramblock-id", + "migration-param.block-bitmap-mapping", );
@@ -1549,6 +1550,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "migrate-set-parameters/arg-type/xbzrle-cache-size", QEMU_CAPS_MIGRATION_PARAM_XBZRLE_CACHE_SIZE }, { "set-numa-node/arg-type/+hmat-lb", QEMU_CAPS_NUMA_HMAT }, { "netdev_add/arg-type/+vhost-vdpa", QEMU_CAPS_NETDEV_VHOST_VDPA }, + { "migrate-set-parameters/arg-type/block-bitmap-mapping/transform", QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING }, };
So how is it possible this change is not reflected in tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml after the previous patch updated QEMU replies? Interestingly enough, tests pass after this patch so either the capability detection is not working or QEMU replies do not actually contain what you're looking for here.
Oops, there's a mistake in the query string where I've missed 'bitmaps' subcomponent. Well actually I've already noticed this before, but squashed the changes to a patch that I've ultimately removed from the series ...
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c7ab144a8e..0e0926d0e5 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -1550,7 +1550,8 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "migrate-set-parameters/arg-type/xbzrle-cache-size", QEMU_CAPS_MIGRATION_PARAM_XBZRLE_CACHE_SIZE }, { "set-numa-node/arg-type/+hmat-lb", QEMU_CAPS_NUMA_HMAT }, { "netdev_add/arg-type/+vhost-vdpa", QEMU_CAPS_NETDEV_VHOST_VDPA }, - { "migrate-set-parameters/arg-type/block-bitmap-mapping/transform", QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING }, + { "migrate-set-parameters/arg-type/block-bitmap-mapping/bitmaps/transform", + QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING }, };
typedef struct _virQEMUCapsObjectTypeProps virQEMUCapsObjectTypeProps; diff --git a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml index f2ec32e46b..b9a36cb71e 100644 --- a/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_6.0.0.x86_64.xml @@ -255,6 +255,7 @@ <flag name='vhost-user-blk'/> <flag name='cpu-max'/> <flag name='memory-backend-file.x-use-canonical-path-for-ramblock-id'/> + <flag name='migration-param.block-bitmap-mapping'/> <version>5002050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100242</microcodeVersion>
With these two hunks squashed in Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

Such images don't support stuff like dirty bitmaps. Note that the synthetic test for detecting bitmaps is used as an example to prevent adding additional test cases. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.h | 3 +++ src/qemu/qemu_monitor_json.c | 11 +++++++++++ tests/qemublocktest.c | 2 ++ tests/qemublocktestdata/bitmap/synthetic.json | 2 +- tests/qemublocktestdata/bitmap/synthetic.out | 1 + 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index b0068f2a82..7a039641ba 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -732,6 +732,9 @@ struct _qemuBlockNamedNodeData { /* the cluster size of the image is valid only when > 0 */ unsigned long long clusterSize; + + /* image version */ + bool qcow2v2; }; GHashTable * diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index d3b2a2c7a5..65c30e3bb4 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2979,6 +2979,7 @@ qemuMonitorJSONBlockGetNamedNodeDataWorker(size_t pos G_GNUC_UNUSED, GHashTable *nodes = opaque; virJSONValuePtr img; virJSONValuePtr bitmaps; + virJSONValuePtr format_specific; const char *nodename; g_autoptr(qemuBlockNamedNodeData) ent = NULL; @@ -3001,6 +3002,16 @@ qemuMonitorJSONBlockGetNamedNodeDataWorker(size_t pos G_GNUC_UNUSED, if ((bitmaps = virJSONValueObjectGetArray(val, "dirty-bitmaps"))) qemuMonitorJSONBlockGetNamedNodeDataBitmaps(bitmaps, ent); + /* query qcow2 format specific props */ + if ((format_specific = virJSONValueObjectGetObject(img, "format-specific")) && + STREQ_NULLABLE(virJSONValueObjectGetString(format_specific, "type"), "qcow2")) { + virJSONValuePtr qcow2props = virJSONValueObjectGetObject(format_specific, "data"); + + if (qcow2props && + STREQ_NULLABLE(virJSONValueObjectGetString(qcow2props, "compat"), "0.10")) + ent->qcow2v2 = true; + } + if (virHashAddEntry(nodes, nodename, ent) < 0) return -1; diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c index ddaf73359d..bbfcfee92d 100644 --- a/tests/qemublocktest.c +++ b/tests/qemublocktest.c @@ -599,6 +599,8 @@ testQemuDetectBitmapsWorker(GHashTable *nodedata, return; virBufferAsprintf(buf, "%s:\n", nodename); + if (data->qcow2v2) + virBufferAddLit(buf, " qcow2 v2\n"); virBufferAdjustIndent(buf, 1); for (i = 0; i < data->nbitmaps; i++) { diff --git a/tests/qemublocktestdata/bitmap/synthetic.json b/tests/qemublocktestdata/bitmap/synthetic.json index 3712c8e5fc..cd468a42a2 100644 --- a/tests/qemublocktestdata/bitmap/synthetic.json +++ b/tests/qemublocktestdata/bitmap/synthetic.json @@ -12,7 +12,7 @@ "format-specific": { "type": "qcow2", "data": { - "compat": "1.1", + "compat": "0.10", "compression-type": "zlib", "lazy-refcounts": false, "bitmaps": [ diff --git a/tests/qemublocktestdata/bitmap/synthetic.out b/tests/qemublocktestdata/bitmap/synthetic.out index cde7228e01..2d9545fc9b 100644 --- a/tests/qemublocktestdata/bitmap/synthetic.out +++ b/tests/qemublocktestdata/bitmap/synthetic.out @@ -1,4 +1,5 @@ libvirt-1-format: + qcow2 v2 current: record:1 busy:0 persist:1 inconsist:1 gran:65536 dirty:0 top-ok: record:1 busy:0 persist:1 inconsist:0 gran:65536 dirty:0 top-inactive: record:0 busy:0 persist:1 inconsist:0 gran:65536 dirty:0 -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:42 +0100, Peter Krempa wrote:
Such images don't support stuff like dirty bitmaps. Note that the synthetic test for detecting bitmaps is used as an example to prevent adding additional test cases.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.h | 3 +++ src/qemu/qemu_monitor_json.c | 11 +++++++++++ tests/qemublocktest.c | 2 ++ tests/qemublocktestdata/bitmap/synthetic.json | 2 +- tests/qemublocktestdata/bitmap/synthetic.out | 1 + 5 files changed, 18 insertions(+), 1 deletion(-)
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

It's already initialized to '1'. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/libvirt-domain.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index dba89a7d3a..e9688a15b4 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -3089,7 +3089,6 @@ virDomainMigrateVersion3Full(virDomainPtr domain, virTypedParamsReplaceString(¶ms, &nparams, VIR_MIGRATE_PARAM_URI, uri_out) < 0) { - cancelled = 1; virErrorPreserveLast(&orig_err); goto finish; } @@ -3098,7 +3097,6 @@ virDomainMigrateVersion3Full(virDomainPtr domain, VIR_MIGRATE_PARAM_URI, &uri) <= 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("domainMigratePrepare3 did not set uri")); - cancelled = 1; virErrorPreserveLast(&orig_err); goto finish; } -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:43 +0100, Peter Krempa wrote:
It's already initialized to '1'.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/libvirt-domain.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index dba89a7d3a..e9688a15b4 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -3089,7 +3089,6 @@ virDomainMigrateVersion3Full(virDomainPtr domain, virTypedParamsReplaceString(¶ms, &nparams, VIR_MIGRATE_PARAM_URI, uri_out) < 0) { - cancelled = 1; virErrorPreserveLast(&orig_err); goto finish; } @@ -3098,7 +3097,6 @@ virDomainMigrateVersion3Full(virDomainPtr domain, VIR_MIGRATE_PARAM_URI, &uri) <= 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("domainMigratePrepare3 did not set uri")); - cancelled = 1; virErrorPreserveLast(&orig_err); goto finish; }
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

Use g_autofree for 'dom_xml' to free it on some of the (unlikely) code paths jumping to cleanup prior to the deallocation which is done right after it's not needed any more since it's a big string. Noticed when running under valgrind: ==2204780== 8,192 bytes in 1 blocks are definitely lost in loss record 2,539 of 2,551 ==2204780== at 0x483BCE8: realloc (vg_replace_malloc.c:834) ==2204780== by 0x4D890DF: g_realloc (in /usr/lib64/libglib-2.0.so.0.6600.4) ==2204780== by 0x4DA3AF0: g_string_append_vprintf (in /usr/lib64/libglib-2.0.so.0.6600.4) ==2204780== by 0x4917293: virBufferAsprintf (virbuffer.c:307) ==2204780== by 0x49B0B75: virDomainChrDefFormat (domain_conf.c:26109) ==2204780== by 0x49E25EF: virDomainDefFormatInternalSetRootName (domain_conf.c:28956) ==2204780== by 0x15F81D24: qemuDomainDefFormatBufInternal (qemu_domain.c:6204) ==2204780== by 0x15F8270D: qemuDomainDefFormatXMLInternal (qemu_domain.c:6229) ==2204780== by 0x15F8270D: qemuDomainDefFormatLive (qemu_domain.c:6279) ==2204780== by 0x15FD8100: qemuMigrationSrcBeginPhase (qemu_migration.c:2395) ==2204780== by 0x15FE0F0D: qemuMigrationSrcPerformPeer2Peer3 (qemu_migration.c:4640) ==2204780== by 0x15FE0F0D: qemuMigrationSrcPerformPeer2Peer (qemu_migration.c:5093) ==2204780== by 0x15FE0F0D: qemuMigrationSrcPerformJob (qemu_migration.c:5168) ==2204780== by 0x15FE280E: qemuMigrationSrcPerform (qemu_migration.c:5372) ==2204780== by 0x15F9BA3D: qemuDomainMigratePerform3Params (qemu_driver.c:11841) Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index f44d31c971..37f0d43d24 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -4347,7 +4347,7 @@ qemuMigrationSrcPerformPeer2Peer3(virQEMUDriverPtr driver, char *uri_out = NULL; char *cookiein = NULL; char *cookieout = NULL; - char *dom_xml = NULL; + g_autofree char *dom_xml = NULL; int cookieinlen = 0; int cookieoutlen = 0; int ret = -1; -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:44 +0100, Peter Krempa wrote:
Use g_autofree for 'dom_xml' to free it on some of the (unlikely) code paths jumping to cleanup prior to the deallocation which is done right after it's not needed any more since it's a big string.
Noticed when running under valgrind:
==2204780== 8,192 bytes in 1 blocks are definitely lost in loss record 2,539 of 2,551 ==2204780== at 0x483BCE8: realloc (vg_replace_malloc.c:834) ==2204780== by 0x4D890DF: g_realloc (in /usr/lib64/libglib-2.0.so.0.6600.4) ==2204780== by 0x4DA3AF0: g_string_append_vprintf (in /usr/lib64/libglib-2.0.so.0.6600.4) ==2204780== by 0x4917293: virBufferAsprintf (virbuffer.c:307) ==2204780== by 0x49B0B75: virDomainChrDefFormat (domain_conf.c:26109) ==2204780== by 0x49E25EF: virDomainDefFormatInternalSetRootName (domain_conf.c:28956) ==2204780== by 0x15F81D24: qemuDomainDefFormatBufInternal (qemu_domain.c:6204) ==2204780== by 0x15F8270D: qemuDomainDefFormatXMLInternal (qemu_domain.c:6229) ==2204780== by 0x15F8270D: qemuDomainDefFormatLive (qemu_domain.c:6279) ==2204780== by 0x15FD8100: qemuMigrationSrcBeginPhase (qemu_migration.c:2395) ==2204780== by 0x15FE0F0D: qemuMigrationSrcPerformPeer2Peer3 (qemu_migration.c:4640) ==2204780== by 0x15FE0F0D: qemuMigrationSrcPerformPeer2Peer (qemu_migration.c:5093) ==2204780== by 0x15FE0F0D: qemuMigrationSrcPerformJob (qemu_migration.c:5168) ==2204780== by 0x15FE280E: qemuMigrationSrcPerform (qemu_migration.c:5372) ==2204780== by 0x15F9BA3D: qemuDomainMigratePerform3Params (qemu_driver.c:11841)
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index f44d31c971..37f0d43d24 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -4347,7 +4347,7 @@ qemuMigrationSrcPerformPeer2Peer3(virQEMUDriverPtr driver, char *uri_out = NULL; char *cookiein = NULL; char *cookieout = NULL; - char *dom_xml = NULL; + g_autofree char *dom_xml = NULL; int cookieinlen = 0; int cookieoutlen = 0; int ret = -1;
Oh wow, the leak has been with us for 10 years since v3 migration protocol was introduced... Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

The suffix is used for output files of 'storagevolxml2argvtest. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- tests/testutils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/testutils.c b/tests/testutils.c index 7ecf7923b8..8734790457 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -332,6 +332,7 @@ virTestRewrapFile(const char *filename) g_autoptr(virCommand) cmd = NULL; if (!(virStringHasSuffix(filename, ".args") || + virStringHasSuffix(filename, ".argv") || virStringHasSuffix(filename, ".ldargs"))) return 0; -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:45 +0100, Peter Krempa wrote:
The suffix is used for output files of 'storagevolxml2argvtest.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- tests/testutils.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tests/testutils.c b/tests/testutils.c index 7ecf7923b8..8734790457 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -332,6 +332,7 @@ virTestRewrapFile(const char *filename) g_autoptr(virCommand) cmd = NULL;
if (!(virStringHasSuffix(filename, ".args") || + virStringHasSuffix(filename, ".argv") || virStringHasSuffix(filename, ".ldargs"))) return 0;
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

Use scripts/test-wrap-argv.py to rewrap the output files so that any further changes don't introduce churn since we are rewrapping the output automatically now. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- tests/storagevolxml2argvdata/iso-input.argv | 6 +++-- tests/storagevolxml2argvdata/iso.argv | 4 +++- .../logical-from-qcow2.argv | 6 +++-- tests/storagevolxml2argvdata/luks-cipher.argv | 8 ++++--- .../luks-convert-encrypt.argv | 23 ++++++++++++------- .../luks-convert-encrypt2fileqcow2.argv | 19 ++++++++++----- .../luks-convert-encrypt2fileraw.argv | 20 ++++++++++------ .../luks-convert-qcow2.argv | 21 +++++++++++------ .../storagevolxml2argvdata/luks-convert.argv | 20 ++++++++++------ tests/storagevolxml2argvdata/luks.argv | 8 ++++--- tests/storagevolxml2argvdata/qcow2-1.1.argv | 8 ++++--- .../storagevolxml2argvdata/qcow2-compat.argv | 8 ++++--- .../qcow2-from-logical-compat.argv | 8 ++++--- tests/storagevolxml2argvdata/qcow2-lazy.argv | 9 +++++--- ...ow2-nobacking-convert-prealloc-compat.argv | 10 +++++--- .../qcow2-nobacking-prealloc-compat.argv | 8 ++++--- .../qcow2-nocapacity-convert-prealloc.argv | 9 +++++--- .../qcow2-nocapacity.argv | 6 ++--- .../qcow2-nocow-compat.argv | 9 +++++--- tests/storagevolxml2argvdata/qcow2-nocow.argv | 9 +++++--- .../qcow2-zerocapacity.argv | 5 +++- 21 files changed, 147 insertions(+), 77 deletions(-) diff --git a/tests/storagevolxml2argvdata/iso-input.argv b/tests/storagevolxml2argvdata/iso-input.argv index 1db0265945..203f27ca22 100644 --- a/tests/storagevolxml2argvdata/iso-input.argv +++ b/tests/storagevolxml2argvdata/iso-input.argv @@ -1,2 +1,4 @@ -qemu-img convert -f raw -O raw /var/lib/libvirt/images/test.iso \ -/var/lib/libvirt/images/sparse.img +qemu-img \ +convert \ +-f raw \ +-O raw /var/lib/libvirt/images/test.iso /var/lib/libvirt/images/sparse.img diff --git a/tests/storagevolxml2argvdata/iso.argv b/tests/storagevolxml2argvdata/iso.argv index 172a255eb8..f74505ecec 100644 --- a/tests/storagevolxml2argvdata/iso.argv +++ b/tests/storagevolxml2argvdata/iso.argv @@ -1 +1,3 @@ -qemu-img create -f raw /var/lib/libvirt/images/test.iso 1024K +qemu-img \ +create \ +-f raw /var/lib/libvirt/images/test.iso 1024K diff --git a/tests/storagevolxml2argvdata/logical-from-qcow2.argv b/tests/storagevolxml2argvdata/logical-from-qcow2.argv index 7beded8478..c1b3cef4b9 100644 --- a/tests/storagevolxml2argvdata/logical-from-qcow2.argv +++ b/tests/storagevolxml2argvdata/logical-from-qcow2.argv @@ -1,2 +1,4 @@ -qemu-img convert -f qcow2 -O raw /var/lib/libvirt/images/OtherDemo.img \ -/dev/HostVG/Swap +qemu-img \ +convert \ +-f qcow2 \ +-O raw /var/lib/libvirt/images/OtherDemo.img /dev/HostVG/Swap diff --git a/tests/storagevolxml2argvdata/luks-cipher.argv b/tests/storagevolxml2argvdata/luks-cipher.argv index a8a19f03ff..bb4438949c 100644 --- a/tests/storagevolxml2argvdata/luks-cipher.argv +++ b/tests/storagevolxml2argvdata/luks-cipher.argv @@ -1,5 +1,7 @@ -qemu-img create -f luks \ +qemu-img \ +create \ +-f luks \ --object secret,id=LuksDemo.img_encrypt0,file=/path/to/secretFile \ -o key-secret=LuksDemo.img_encrypt0,cipher-alg=serpent-256,cipher-mode=cbc,\ -hash-alg=sha256,ivgen-alg=plain64,ivgen-hash-alg=sha256 \ -/var/lib/libvirt/images/LuksDemo.img 5242880K +hash-alg=sha256,ivgen-alg=plain64,\ +ivgen-hash-alg=sha256 /var/lib/libvirt/images/LuksDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/luks-convert-encrypt.argv b/tests/storagevolxml2argvdata/luks-convert-encrypt.argv index 78bce96aaa..456ae621d1 100644 --- a/tests/storagevolxml2argvdata/luks-convert-encrypt.argv +++ b/tests/storagevolxml2argvdata/luks-convert-encrypt.argv @@ -1,11 +1,18 @@ -qemu-img create -f luks \ +qemu-img \ +create \ +-f luks \ --object secret,id=LuksDemo.img_encrypt0,file=/path/to/secretFile \ --o key-secret=LuksDemo.img_encrypt0 \ -/var/lib/libvirt/images/LuksDemo.img 5242880K -qemu-img convert --image-opts -n --target-image-opts \ +-o key-secret=LuksDemo.img_encrypt0 /var/lib/libvirt/images/LuksDemo.img \ +5242880K +qemu-img \ +convert \ +--image-opts \ +-n \ +--target-image-opts \ --object secret,id=LuksDemo.img_encrypt0,file=/path/to/secretFile \ ---object secret,id=OtherDemo.img_encrypt0,file=/path/to/inputSecretFile \ -driver=luks,file.filename=/var/lib/libvirt/images/OtherDemo.img,\ -key-secret=OtherDemo.img_encrypt0 \ -driver=luks,file.filename=/var/lib/libvirt/images/LuksDemo.img,\ +--object secret,id=OtherDemo.img_encrypt0,\ +file=/path/to/inputSecretFile driver=luks,\ +file.filename=/var/lib/libvirt/images/OtherDemo.img,\ +key-secret=OtherDemo.img_encrypt0 driver=luks,\ +file.filename=/var/lib/libvirt/images/LuksDemo.img,\ key-secret=LuksDemo.img_encrypt0 diff --git a/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv index fd974f863e..1320e2ee2f 100644 --- a/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv +++ b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv @@ -1,7 +1,14 @@ -qemu-img create -f qcow2 \ +qemu-img \ +create \ +-f qcow2 \ -o compat=0.10 /var/lib/libvirt/images/sparse-qcow2.img 1073741824K -qemu-img convert --image-opts -n --target-image-opts \ ---object secret,id=OtherDemo.img_encrypt0,file=/path/to/inputSecretFile \ -driver=luks,file.filename=/var/lib/libvirt/images/OtherDemo.img,\ -key-secret=OtherDemo.img_encrypt0 \ -driver=qcow2,file.filename=/var/lib/libvirt/images/sparse-qcow2.img +qemu-img \ +convert \ +--image-opts \ +-n \ +--target-image-opts \ +--object secret,id=OtherDemo.img_encrypt0,\ +file=/path/to/inputSecretFile driver=luks,\ +file.filename=/var/lib/libvirt/images/OtherDemo.img,\ +key-secret=OtherDemo.img_encrypt0 driver=qcow2,\ +file.filename=/var/lib/libvirt/images/sparse-qcow2.img diff --git a/tests/storagevolxml2argvdata/luks-convert-encrypt2fileraw.argv b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileraw.argv index 82473db57b..e140850217 100644 --- a/tests/storagevolxml2argvdata/luks-convert-encrypt2fileraw.argv +++ b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileraw.argv @@ -1,7 +1,13 @@ -qemu-img create -f raw \ -/var/lib/libvirt/images/sparse.img 1073741824K -qemu-img convert --image-opts -n --target-image-opts \ ---object secret,id=OtherDemo.img_encrypt0,file=/path/to/inputSecretFile \ -driver=luks,file.filename=/var/lib/libvirt/images/OtherDemo.img,\ -key-secret=OtherDemo.img_encrypt0 \ -driver=raw,file.filename=/var/lib/libvirt/images/sparse.img +qemu-img \ +create \ +-f raw /var/lib/libvirt/images/sparse.img 1073741824K +qemu-img \ +convert \ +--image-opts \ +-n \ +--target-image-opts \ +--object secret,id=OtherDemo.img_encrypt0,\ +file=/path/to/inputSecretFile driver=luks,\ +file.filename=/var/lib/libvirt/images/OtherDemo.img,\ +key-secret=OtherDemo.img_encrypt0 driver=raw,\ +file.filename=/var/lib/libvirt/images/sparse.img diff --git a/tests/storagevolxml2argvdata/luks-convert-qcow2.argv b/tests/storagevolxml2argvdata/luks-convert-qcow2.argv index 9124f5f27c..78cd9a2a8d 100644 --- a/tests/storagevolxml2argvdata/luks-convert-qcow2.argv +++ b/tests/storagevolxml2argvdata/luks-convert-qcow2.argv @@ -1,9 +1,16 @@ -qemu-img create -f luks \ +qemu-img \ +create \ +-f luks \ --object secret,id=OtherDemo.img_encrypt0,file=/path/to/secretFile \ --o key-secret=OtherDemo.img_encrypt0 \ -/var/lib/libvirt/images/OtherDemo.img 5242880K -qemu-img convert --image-opts -n --target-image-opts \ ---object secret,id=OtherDemo.img_encrypt0,file=/path/to/secretFile \ -driver=qcow2,file.filename=/var/lib/libvirt/images/sparse-qcow2.img \ -driver=luks,file.filename=/var/lib/libvirt/images/OtherDemo.img,\ +-o key-secret=OtherDemo.img_encrypt0 /var/lib/libvirt/images/OtherDemo.img \ +5242880K +qemu-img \ +convert \ +--image-opts \ +-n \ +--target-image-opts \ +--object secret,id=OtherDemo.img_encrypt0,\ +file=/path/to/secretFile driver=qcow2,\ +file.filename=/var/lib/libvirt/images/sparse-qcow2.img driver=luks,\ +file.filename=/var/lib/libvirt/images/OtherDemo.img,\ key-secret=OtherDemo.img_encrypt0 diff --git a/tests/storagevolxml2argvdata/luks-convert.argv b/tests/storagevolxml2argvdata/luks-convert.argv index 6bac814300..e4a8277d7f 100644 --- a/tests/storagevolxml2argvdata/luks-convert.argv +++ b/tests/storagevolxml2argvdata/luks-convert.argv @@ -1,9 +1,15 @@ -qemu-img create -f luks \ +qemu-img \ +create \ +-f luks \ --object secret,id=OtherDemo.img_encrypt0,file=/path/to/secretFile \ --o key-secret=OtherDemo.img_encrypt0 \ -/var/lib/libvirt/images/OtherDemo.img 5242880K -qemu-img convert --image-opts -n --target-image-opts \ ---object secret,id=OtherDemo.img_encrypt0,file=/path/to/secretFile \ -driver=raw,file.filename=/var/lib/libvirt/images/sparse.img \ -driver=luks,file.filename=/var/lib/libvirt/images/OtherDemo.img,\ +-o key-secret=OtherDemo.img_encrypt0 /var/lib/libvirt/images/OtherDemo.img \ +5242880K +qemu-img \ +convert \ +--image-opts \ +-n \ +--target-image-opts \ +--object secret,id=OtherDemo.img_encrypt0,file=/path/to/secretFile driver=raw,\ +file.filename=/var/lib/libvirt/images/sparse.img driver=luks,\ +file.filename=/var/lib/libvirt/images/OtherDemo.img,\ key-secret=OtherDemo.img_encrypt0 diff --git a/tests/storagevolxml2argvdata/luks.argv b/tests/storagevolxml2argvdata/luks.argv index 336238ecab..5013c8ca7f 100644 --- a/tests/storagevolxml2argvdata/luks.argv +++ b/tests/storagevolxml2argvdata/luks.argv @@ -1,4 +1,6 @@ -qemu-img create -f luks \ +qemu-img \ +create \ +-f luks \ --object secret,id=LuksDemo.img_encrypt0,file=/path/to/secretFile \ --o key-secret=LuksDemo.img_encrypt0 \ -/var/lib/libvirt/images/LuksDemo.img 5242880K +-o key-secret=LuksDemo.img_encrypt0 /var/lib/libvirt/images/LuksDemo.img \ +5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-1.1.argv b/tests/storagevolxml2argvdata/qcow2-1.1.argv index 71ff67378e..5ee974afe9 100644 --- a/tests/storagevolxml2argvdata/qcow2-1.1.argv +++ b/tests/storagevolxml2argvdata/qcow2-1.1.argv @@ -1,3 +1,5 @@ -qemu-img create -f qcow2 -b /dev/null \ --o backing_fmt=raw,compat=1.1 \ -/var/lib/libvirt/images/OtherDemo.img 5242880K +qemu-img \ +create \ +-f qcow2 \ +-b /dev/null \ +-o backing_fmt=raw,compat=1.1 /var/lib/libvirt/images/OtherDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-compat.argv b/tests/storagevolxml2argvdata/qcow2-compat.argv index fcb6bed782..3071d7a790 100644 --- a/tests/storagevolxml2argvdata/qcow2-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-compat.argv @@ -1,3 +1,5 @@ -qemu-img create -f qcow2 -b /dev/null \ --o backing_fmt=raw,compat=0.10 \ -/var/lib/libvirt/images/OtherDemo.img 5242880K +qemu-img \ +create \ +-f qcow2 \ +-b /dev/null \ +-o backing_fmt=raw,compat=0.10 /var/lib/libvirt/images/OtherDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv b/tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv index f99717ad40..1971da200d 100644 --- a/tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv @@ -1,3 +1,5 @@ -qemu-img convert -f raw -O qcow2 \ --o compat=0.10 \ -/dev/HostVG/Swap /var/lib/libvirt/images/OtherDemo.img +qemu-img \ +convert \ +-f raw \ +-O qcow2 \ +-o compat=0.10 /dev/HostVG/Swap /var/lib/libvirt/images/OtherDemo.img diff --git a/tests/storagevolxml2argvdata/qcow2-lazy.argv b/tests/storagevolxml2argvdata/qcow2-lazy.argv index c3c09cefef..2621b01168 100644 --- a/tests/storagevolxml2argvdata/qcow2-lazy.argv +++ b/tests/storagevolxml2argvdata/qcow2-lazy.argv @@ -1,3 +1,6 @@ -qemu-img create -f qcow2 -b /dev/null \ --o backing_fmt=raw,compat=1.1,lazy_refcounts \ -/var/lib/libvirt/images/OtherDemo.img 5242880K +qemu-img \ +create \ +-f qcow2 \ +-b /dev/null \ +-o backing_fmt=raw,compat=1.1,\ +lazy_refcounts /var/lib/libvirt/images/OtherDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-nobacking-convert-prealloc-compat.argv b/tests/storagevolxml2argvdata/qcow2-nobacking-convert-prealloc-compat.argv index f3e230654b..87489641d5 100644 --- a/tests/storagevolxml2argvdata/qcow2-nobacking-convert-prealloc-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-nobacking-convert-prealloc-compat.argv @@ -1,3 +1,7 @@ -qemu-img convert -f raw -O qcow2 \ --o preallocation=metadata,compat=0.10 \ -/var/lib/libvirt/images/sparse.img /var/lib/libvirt/images/OtherDemo.img +qemu-img \ +convert \ +-f raw \ +-O qcow2 \ +-o preallocation=metadata,\ +compat=0.10 /var/lib/libvirt/images/sparse.img \ +/var/lib/libvirt/images/OtherDemo.img diff --git a/tests/storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv b/tests/storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv index 841d683965..a883030744 100644 --- a/tests/storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv @@ -1,3 +1,5 @@ -qemu-img create -f qcow2 \ --o preallocation=metadata,compat=0.10 \ -/var/lib/libvirt/images/OtherDemo.img 5242880K +qemu-img \ +create \ +-f qcow2 \ +-o preallocation=metadata,\ +compat=0.10 /var/lib/libvirt/images/OtherDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-nocapacity-convert-prealloc.argv b/tests/storagevolxml2argvdata/qcow2-nocapacity-convert-prealloc.argv index 22dd9381a4..049d2d73b5 100644 --- a/tests/storagevolxml2argvdata/qcow2-nocapacity-convert-prealloc.argv +++ b/tests/storagevolxml2argvdata/qcow2-nocapacity-convert-prealloc.argv @@ -1,4 +1,7 @@ -qemu-img convert -f raw -O qcow2 \ --o preallocation=falloc,compat=0.10 \ -/var/lib/libvirt/images/sparse.img \ +qemu-img \ +convert \ +-f raw \ +-O qcow2 \ +-o preallocation=falloc,\ +compat=0.10 /var/lib/libvirt/images/sparse.img \ /var/lib/libvirt/images/OtherDemo.img diff --git a/tests/storagevolxml2argvdata/qcow2-nocapacity.argv b/tests/storagevolxml2argvdata/qcow2-nocapacity.argv index a922d12042..30bcfb00c7 100644 --- a/tests/storagevolxml2argvdata/qcow2-nocapacity.argv +++ b/tests/storagevolxml2argvdata/qcow2-nocapacity.argv @@ -1,5 +1,5 @@ -qemu-img create \ +qemu-img \ +create \ -f qcow2 \ -b /dev/null \ --o backing_fmt=raw,compat=0.10 \ -/var/lib/libvirt/images/OtherDemo.img +-o backing_fmt=raw,compat=0.10 /var/lib/libvirt/images/OtherDemo.img diff --git a/tests/storagevolxml2argvdata/qcow2-nocow-compat.argv b/tests/storagevolxml2argvdata/qcow2-nocow-compat.argv index 826001f73b..5e327dab0b 100644 --- a/tests/storagevolxml2argvdata/qcow2-nocow-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-nocow-compat.argv @@ -1,3 +1,6 @@ -qemu-img create -f qcow2 -b /dev/null \ --o backing_fmt=raw,nocow=on,compat=0.10 \ -/var/lib/libvirt/images/OtherDemo.img 5242880K +qemu-img \ +create \ +-f qcow2 \ +-b /dev/null \ +-o backing_fmt=raw,nocow=on,\ +compat=0.10 /var/lib/libvirt/images/OtherDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-nocow.argv b/tests/storagevolxml2argvdata/qcow2-nocow.argv index e54801c78a..74eaa89835 100644 --- a/tests/storagevolxml2argvdata/qcow2-nocow.argv +++ b/tests/storagevolxml2argvdata/qcow2-nocow.argv @@ -1,3 +1,6 @@ -qemu-img create -f qcow2 -b /dev/null \ --o backing_fmt=raw,encryption=on,nocow=on \ -/var/lib/libvirt/images/OtherDemo.img 5242880K +qemu-img \ +create \ +-f qcow2 \ +-b /dev/null \ +-o backing_fmt=raw,encryption=on,\ +nocow=on /var/lib/libvirt/images/OtherDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-zerocapacity.argv b/tests/storagevolxml2argvdata/qcow2-zerocapacity.argv index 45894931ae..95dfc65d9b 100644 --- a/tests/storagevolxml2argvdata/qcow2-zerocapacity.argv +++ b/tests/storagevolxml2argvdata/qcow2-zerocapacity.argv @@ -1 +1,4 @@ -qemu-img create -f qcow2 -o compat=0.10 /var/lib/libvirt/images/OtherDemo.img 0K +qemu-img \ +create \ +-f qcow2 \ +-o compat=0.10 /var/lib/libvirt/images/OtherDemo.img 0K -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:46 +0100, Peter Krempa wrote:
Use scripts/test-wrap-argv.py to rewrap the output files so that any further changes don't introduce churn since we are rewrapping the output automatically now.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- tests/storagevolxml2argvdata/iso-input.argv | 6 +++-- tests/storagevolxml2argvdata/iso.argv | 4 +++- .../logical-from-qcow2.argv | 6 +++-- tests/storagevolxml2argvdata/luks-cipher.argv | 8 ++++--- .../luks-convert-encrypt.argv | 23 ++++++++++++------- .../luks-convert-encrypt2fileqcow2.argv | 19 ++++++++++----- .../luks-convert-encrypt2fileraw.argv | 20 ++++++++++------ .../luks-convert-qcow2.argv | 21 +++++++++++------ .../storagevolxml2argvdata/luks-convert.argv | 20 ++++++++++------ tests/storagevolxml2argvdata/luks.argv | 8 ++++--- tests/storagevolxml2argvdata/qcow2-1.1.argv | 8 ++++--- .../storagevolxml2argvdata/qcow2-compat.argv | 8 ++++--- .../qcow2-from-logical-compat.argv | 8 ++++--- tests/storagevolxml2argvdata/qcow2-lazy.argv | 9 +++++--- ...ow2-nobacking-convert-prealloc-compat.argv | 10 +++++--- .../qcow2-nobacking-prealloc-compat.argv | 8 ++++--- .../qcow2-nocapacity-convert-prealloc.argv | 9 +++++--- .../qcow2-nocapacity.argv | 6 ++--- .../qcow2-nocow-compat.argv | 9 +++++--- tests/storagevolxml2argvdata/qcow2-nocow.argv | 9 +++++--- .../qcow2-zerocapacity.argv | 5 +++- 21 files changed, 147 insertions(+), 77 deletions(-)
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

Format the new volumes with 'compat=1.1' since the minimum supported qemu version is now 1.5 rather the pre-historic compat=0.10. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/storage/storage_util.c | 2 +- .../storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv | 2 +- tests/storagevolxml2argvdata/qcow2-compat.argv | 2 +- tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv | 2 +- tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt.argv | 2 +- .../qcow2-luks-convert-encrypt2fileqcow2.argv | 2 +- tests/storagevolxml2argvdata/qcow2-luks.argv | 2 +- .../qcow2-nobacking-convert-prealloc-compat.argv | 2 +- .../storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv | 2 +- .../qcow2-nocapacity-convert-prealloc.argv | 2 +- tests/storagevolxml2argvdata/qcow2-nocapacity.argv | 2 +- tests/storagevolxml2argvdata/qcow2-nocow-compat.argv | 2 +- tests/storagevolxml2argvdata/qcow2-zerocapacity.argv | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index b5adb05826..6d8dd3cc16 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -777,7 +777,7 @@ storageBackendCreateQemuImgOpts(virStorageEncryptionInfoDefPtr encinfo, if (info->compat) virBufferAsprintf(&buf, "compat=%s,", info->compat); else if (info->format == VIR_STORAGE_FILE_QCOW2) - virBufferAddLit(&buf, "compat=0.10,"); + virBufferAddLit(&buf, "compat=1.1,"); if (info->features && info->format == VIR_STORAGE_FILE_QCOW2) { if (virBitmapIsBitSet(info->features, diff --git a/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv index 1320e2ee2f..c313a04fb3 100644 --- a/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv +++ b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv @@ -1,7 +1,7 @@ qemu-img \ create \ -f qcow2 \ --o compat=0.10 /var/lib/libvirt/images/sparse-qcow2.img 1073741824K +-o compat=1.1 /var/lib/libvirt/images/sparse-qcow2.img 1073741824K qemu-img \ convert \ --image-opts \ diff --git a/tests/storagevolxml2argvdata/qcow2-compat.argv b/tests/storagevolxml2argvdata/qcow2-compat.argv index 3071d7a790..5ee974afe9 100644 --- a/tests/storagevolxml2argvdata/qcow2-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-compat.argv @@ -2,4 +2,4 @@ qemu-img \ create \ -f qcow2 \ -b /dev/null \ --o backing_fmt=raw,compat=0.10 /var/lib/libvirt/images/OtherDemo.img 5242880K +-o backing_fmt=raw,compat=1.1 /var/lib/libvirt/images/OtherDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv b/tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv index 1971da200d..dcafffc3a4 100644 --- a/tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv @@ -2,4 +2,4 @@ qemu-img \ convert \ -f raw \ -O qcow2 \ --o compat=0.10 /dev/HostVG/Swap /var/lib/libvirt/images/OtherDemo.img +-o compat=1.1 /dev/HostVG/Swap /var/lib/libvirt/images/OtherDemo.img diff --git a/tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt.argv b/tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt.argv index de8aef4233..891746d921 100644 --- a/tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt.argv +++ b/tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt.argv @@ -3,7 +3,7 @@ create \ -f qcow2 \ --object secret,id=OtherDemoLuks.img_encrypt0,file=/path/to/secretFile \ -o encrypt.format=luks,encrypt.key-secret=OtherDemoLuks.img_encrypt0,\ -compat=0.10 /var/lib/libvirt/images/OtherDemoLuks.img 5242880K +compat=1.1 /var/lib/libvirt/images/OtherDemoLuks.img 5242880K qemu-img \ convert \ --image-opts \ diff --git a/tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt2fileqcow2.argv b/tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt2fileqcow2.argv index 517156ca83..fc9c4ab825 100644 --- a/tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt2fileqcow2.argv +++ b/tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt2fileqcow2.argv @@ -1,7 +1,7 @@ qemu-img \ create \ -f qcow2 \ --o compat=0.10 /var/lib/libvirt/images/sparse-qcow2.img 1073741824K +-o compat=1.1 /var/lib/libvirt/images/sparse-qcow2.img 1073741824K qemu-img \ convert \ --image-opts \ diff --git a/tests/storagevolxml2argvdata/qcow2-luks.argv b/tests/storagevolxml2argvdata/qcow2-luks.argv index 4b51b374ca..c0568e10e3 100644 --- a/tests/storagevolxml2argvdata/qcow2-luks.argv +++ b/tests/storagevolxml2argvdata/qcow2-luks.argv @@ -5,4 +5,4 @@ create \ --object secret,id=OtherDemoLuks.img_encrypt0,file=/path/to/secretFile \ -o backing_fmt=raw,encrypt.format=luks,\ encrypt.key-secret=OtherDemoLuks.img_encrypt0,\ -compat=0.10 /var/lib/libvirt/images/OtherDemoLuks.img 5242880K +compat=1.1 /var/lib/libvirt/images/OtherDemoLuks.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-nobacking-convert-prealloc-compat.argv b/tests/storagevolxml2argvdata/qcow2-nobacking-convert-prealloc-compat.argv index 87489641d5..c237ab0cc9 100644 --- a/tests/storagevolxml2argvdata/qcow2-nobacking-convert-prealloc-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-nobacking-convert-prealloc-compat.argv @@ -3,5 +3,5 @@ convert \ -f raw \ -O qcow2 \ -o preallocation=metadata,\ -compat=0.10 /var/lib/libvirt/images/sparse.img \ +compat=1.1 /var/lib/libvirt/images/sparse.img \ /var/lib/libvirt/images/OtherDemo.img diff --git a/tests/storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv b/tests/storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv index a883030744..fa83143b5e 100644 --- a/tests/storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv @@ -2,4 +2,4 @@ qemu-img \ create \ -f qcow2 \ -o preallocation=metadata,\ -compat=0.10 /var/lib/libvirt/images/OtherDemo.img 5242880K +compat=1.1 /var/lib/libvirt/images/OtherDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-nocapacity-convert-prealloc.argv b/tests/storagevolxml2argvdata/qcow2-nocapacity-convert-prealloc.argv index 049d2d73b5..f62da6fabe 100644 --- a/tests/storagevolxml2argvdata/qcow2-nocapacity-convert-prealloc.argv +++ b/tests/storagevolxml2argvdata/qcow2-nocapacity-convert-prealloc.argv @@ -3,5 +3,5 @@ convert \ -f raw \ -O qcow2 \ -o preallocation=falloc,\ -compat=0.10 /var/lib/libvirt/images/sparse.img \ +compat=1.1 /var/lib/libvirt/images/sparse.img \ /var/lib/libvirt/images/OtherDemo.img diff --git a/tests/storagevolxml2argvdata/qcow2-nocapacity.argv b/tests/storagevolxml2argvdata/qcow2-nocapacity.argv index 30bcfb00c7..d696af60d7 100644 --- a/tests/storagevolxml2argvdata/qcow2-nocapacity.argv +++ b/tests/storagevolxml2argvdata/qcow2-nocapacity.argv @@ -2,4 +2,4 @@ qemu-img \ create \ -f qcow2 \ -b /dev/null \ --o backing_fmt=raw,compat=0.10 /var/lib/libvirt/images/OtherDemo.img +-o backing_fmt=raw,compat=1.1 /var/lib/libvirt/images/OtherDemo.img diff --git a/tests/storagevolxml2argvdata/qcow2-nocow-compat.argv b/tests/storagevolxml2argvdata/qcow2-nocow-compat.argv index 5e327dab0b..b5d18ccc12 100644 --- a/tests/storagevolxml2argvdata/qcow2-nocow-compat.argv +++ b/tests/storagevolxml2argvdata/qcow2-nocow-compat.argv @@ -3,4 +3,4 @@ create \ -f qcow2 \ -b /dev/null \ -o backing_fmt=raw,nocow=on,\ -compat=0.10 /var/lib/libvirt/images/OtherDemo.img 5242880K +compat=1.1 /var/lib/libvirt/images/OtherDemo.img 5242880K diff --git a/tests/storagevolxml2argvdata/qcow2-zerocapacity.argv b/tests/storagevolxml2argvdata/qcow2-zerocapacity.argv index 95dfc65d9b..bc6e5ee758 100644 --- a/tests/storagevolxml2argvdata/qcow2-zerocapacity.argv +++ b/tests/storagevolxml2argvdata/qcow2-zerocapacity.argv @@ -1,4 +1,4 @@ qemu-img \ create \ -f qcow2 \ --o compat=0.10 /var/lib/libvirt/images/OtherDemo.img 0K +-o compat=1.1 /var/lib/libvirt/images/OtherDemo.img 0K -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:47 +0100, Peter Krempa wrote:
Format the new volumes with 'compat=1.1' since the minimum supported qemu version is now 1.5 rather the pre-historic compat=0.10.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/storage/storage_util.c | 2 +- .../storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv | 2 +- tests/storagevolxml2argvdata/qcow2-compat.argv | 2 +- tests/storagevolxml2argvdata/qcow2-from-logical-compat.argv | 2 +- tests/storagevolxml2argvdata/qcow2-luks-convert-encrypt.argv | 2 +- .../qcow2-luks-convert-encrypt2fileqcow2.argv | 2 +- tests/storagevolxml2argvdata/qcow2-luks.argv | 2 +- .../qcow2-nobacking-convert-prealloc-compat.argv | 2 +- .../storagevolxml2argvdata/qcow2-nobacking-prealloc-compat.argv | 2 +- .../qcow2-nocapacity-convert-prealloc.argv | 2 +- tests/storagevolxml2argvdata/qcow2-nocapacity.argv | 2 +- tests/storagevolxml2argvdata/qcow2-nocow-compat.argv | 2 +- tests/storagevolxml2argvdata/qcow2-zerocapacity.argv | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-)
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

On Thu, Feb 11, 2021 at 04:37:47PM +0100, Peter Krempa wrote:
Format the new volumes with 'compat=1.1' since the minimum supported qemu version is now 1.5 rather the pre-historic compat=0.10.
I understand the desire to do this, but this is none the less a semantic change to the behaviour of the APIs. It is the same situation as arbitrarily changing the defaults for any part of the domain XML. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Fri, Feb 12, 2021 at 10:49:02 +0000, Daniel Berrange wrote:
On Thu, Feb 11, 2021 at 04:37:47PM +0100, Peter Krempa wrote:
Format the new volumes with 'compat=1.1' since the minimum supported qemu version is now 1.5 rather the pre-historic compat=0.10.
I understand the desire to do this, but this is none the less a semantic change to the behaviour of the APIs. It is the same situation as arbitrarily changing the defaults for any part of the domain XML.
I'm aware of that, but at certain point it IMO doesn't make sense to try to stick with a prehistoric format just for the sake of it and IMO this is it. Nonetheless, it's not strictly required. I can just use the new format for the non-shared-storage migration rather than globally if we want to stay in the cave.

On Fri, Feb 12, 2021 at 11:55:36AM +0100, Peter Krempa wrote:
On Fri, Feb 12, 2021 at 10:49:02 +0000, Daniel Berrange wrote:
On Thu, Feb 11, 2021 at 04:37:47PM +0100, Peter Krempa wrote:
Format the new volumes with 'compat=1.1' since the minimum supported qemu version is now 1.5 rather the pre-historic compat=0.10.
I understand the desire to do this, but this is none the less a semantic change to the behaviour of the APIs. It is the same situation as arbitrarily changing the defaults for any part of the domain XML.
I'm aware of that, but at certain point it IMO doesn't make sense to try to stick with a prehistoric format just for the sake of it and IMO this is it.
Well that's a policy decision and it is upto the user or mgmt app to decide when they wish to drop compatibility with old distros. RHEL had continued to publish its cloud images with old format until very recently for sake of compat. I don't think libvirt should be forcing that decision onto people as it sabotages libvirt's value of providing long term stable behaviour to applications. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

On Fri, Feb 12, 2021 at 12:13:58 +0000, Daniel P. Berrangé wrote:
On Fri, Feb 12, 2021 at 11:55:36AM +0100, Peter Krempa wrote:
On Fri, Feb 12, 2021 at 10:49:02 +0000, Daniel Berrange wrote:
On Thu, Feb 11, 2021 at 04:37:47PM +0100, Peter Krempa wrote:
Format the new volumes with 'compat=1.1' since the minimum supported qemu version is now 1.5 rather the pre-historic compat=0.10.
I understand the desire to do this, but this is none the less a semantic change to the behaviour of the APIs. It is the same situation as arbitrarily changing the defaults for any part of the domain XML.
I'm aware of that, but at certain point it IMO doesn't make sense to try to stick with a prehistoric format just for the sake of it and IMO this is it.
Well that's a policy decision and it is upto the user or mgmt app to decide when they wish to drop compatibility with old distros. RHEL had continued to publish its cloud images with old format until very recently for sake of compat. I don't think libvirt should be forcing that decision onto people as it sabotages libvirt's value of providing long term stable behaviour to applications.
The oldest QEMU release we support understands v3 so there's no reason to use an older format in this respect. But you're right there might be other use cases which would still need v2 format for compatibility. I guess I was too focused on our usage and libvirt/QEMU compatibility when reviewing the patch. Jirka

The non-transaction wrapper is useful for code paths which want to delete individual bitmaps or for cleanup after a failed job where we want to attempt to delete every bitmap individually to prevent a failure from cleaning up the rest. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.c | 13 +++++++++++++ src/qemu/qemu_monitor.h | 5 +++++ src/qemu/qemu_monitor_json.c | 24 ++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 ++++++ tests/qemumonitorjsontest.c | 2 ++ 5 files changed, 50 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 14966d4096..2fb7d6569b 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4645,6 +4645,19 @@ qemuMonitorTransactionBitmapRemove(virJSONValuePtr actions, } +int +qemuMonitorBitmapRemove(qemuMonitorPtr mon, + const char *node, + const char *name) +{ + VIR_DEBUG("node='%s', name='%s'", node, name); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONBitmapRemove(mon, node, name); +} + + int qemuMonitorTransactionBitmapEnable(virJSONValuePtr actions, const char *node, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 7a039641ba..544611b443 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1478,6 +1478,11 @@ int qemuMonitorTransactionBitmapRemove(virJSONValuePtr actions, const char *node, const char *name); + +int +qemuMonitorBitmapRemove(qemuMonitorPtr mon, + const char *node, + const char *name); int qemuMonitorTransactionBitmapEnable(virJSONValuePtr actions, const char *node, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 65c30e3bb4..f19bb589b2 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -9253,6 +9253,30 @@ qemuMonitorJSONTransactionBitmapRemove(virJSONValuePtr actions, } +int +qemuMonitorJSONBitmapRemove(qemuMonitorPtr mon, + const char *node, + const char *name) +{ + g_autoptr(virJSONValue) cmd = NULL; + g_autoptr(virJSONValue) reply = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("block-dirty-bitmap-remove", + "s:node", node, + "s:name", name, + NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + return -1; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + return -1; + + return 0; +} + + int qemuMonitorJSONTransactionBitmapEnable(virJSONValuePtr actions, const char *node, diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index ba1531fee8..8e2ab24a59 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -659,6 +659,12 @@ int qemuMonitorJSONTransactionBitmapRemove(virJSONValuePtr actions, const char *node, const char *name); + +int +qemuMonitorJSONBitmapRemove(qemuMonitorPtr mon, + const char *node, + const char *name); + int qemuMonitorJSONTransactionBitmapEnable(virJSONValuePtr actions, const char *node, diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 956423f10f..af02c0b0e6 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1215,6 +1215,7 @@ GEN_TEST_FUNC(qemuMonitorJSONBlockdevTrayOpen, "foodev", true) GEN_TEST_FUNC(qemuMonitorJSONBlockdevTrayClose, "foodev") GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumRemove, "foodev") GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumInsert, "foodev", "newnode") +GEN_TEST_FUNC(qemuMonitorJSONBitmapRemove, "foodev", "newnode") GEN_TEST_FUNC(qemuMonitorJSONJobDismiss, "jobname") GEN_TEST_FUNC(qemuMonitorJSONJobCancel, "jobname", false) GEN_TEST_FUNC(qemuMonitorJSONJobComplete, "jobname") @@ -3132,6 +3133,7 @@ mymain(void) DO_TEST_GEN(qemuMonitorJSONBlockdevTrayClose); DO_TEST_GEN(qemuMonitorJSONBlockdevMediumRemove); DO_TEST_GEN(qemuMonitorJSONBlockdevMediumInsert); + DO_TEST_GEN(qemuMonitorJSONBitmapRemove); DO_TEST_GEN(qemuMonitorJSONJobDismiss); DO_TEST_GEN(qemuMonitorJSONJobCancel); DO_TEST_GEN(qemuMonitorJSONJobComplete); -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:48 +0100, Peter Krempa wrote:
The non-transaction wrapper is useful for code paths which want to delete individual bitmaps or for cleanup after a failed job where we want to attempt to delete every bitmap individually to prevent a failure from cleaning up the rest.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.c | 13 +++++++++++++ src/qemu/qemu_monitor.h | 5 +++++ src/qemu/qemu_monitor_json.c | 24 ++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 ++++++ tests/qemumonitorjsontest.c | 2 ++ 5 files changed, 50 insertions(+)
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

There's no need in the cleanup steps to invoke a transaction to delete a single bitmap. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_blockjob.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index 582fe45c66..aa065b1319 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -1420,7 +1420,6 @@ qemuBlockJobProcessEventFailedActiveCommit(virQEMUDriverPtr driver, qemuDomainAsyncJob asyncJob) { qemuDomainObjPrivatePtr priv = vm->privateData; - g_autoptr(virJSONValue) actions = virJSONValueNewArray(); virDomainDiskDefPtr disk = job->disk; VIR_DEBUG("active commit job '%s' on VM '%s' failed", job->name, vm->def->name); @@ -1428,13 +1427,12 @@ qemuBlockJobProcessEventFailedActiveCommit(virQEMUDriverPtr driver, if (!disk) return; - ignore_value(qemuMonitorTransactionBitmapRemove(actions, disk->mirror->nodeformat, - "libvirt-tmp-activewrite")); - if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0) return; - qemuMonitorTransaction(priv->mon, &actions); + qemuMonitorBitmapRemove(priv->mon, + disk->mirror->nodeformat, + "libvirt-tmp-activewrite"); if (qemuDomainObjExitMonitor(priv->driver, vm) < 0) return; @@ -1502,7 +1500,6 @@ qemuBlockJobProcessEventConcludedBackup(virQEMUDriverPtr driver, unsigned long long progressTotal) { g_autoptr(qemuBlockStorageSourceAttachData) backend = NULL; - g_autoptr(virJSONValue) actions = NULL; qemuBackupNotifyBlockjobEnd(vm, job->disk, newstate, job->errmsg, progressCurrent, progressTotal, asyncJob); @@ -1511,23 +1508,16 @@ qemuBlockJobProcessEventConcludedBackup(virQEMUDriverPtr driver, !(backend = qemuBlockStorageSourceDetachPrepare(job->data.backup.store, NULL))) return; - if (job->data.backup.bitmap) { - actions = virJSONValueNewArray(); - - if (qemuMonitorTransactionBitmapRemove(actions, - job->disk->src->nodeformat, - job->data.backup.bitmap) < 0) - return; - } - if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) return; if (backend) qemuBlockStorageSourceAttachRollback(qemuDomainGetMonitor(vm), backend); - if (actions) - qemuMonitorTransaction(qemuDomainGetMonitor(vm), &actions); + if (job->data.backup.bitmap) + qemuMonitorBitmapRemove(qemuDomainGetMonitor(vm), + job->disk->src->nodeformat, + job->data.backup.bitmap); if (qemuDomainObjExitMonitor(driver, vm) < 0) return; -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:49 +0100, Peter Krempa wrote:
There's no need in the cleanup steps to invoke a transaction to delete a single bitmap.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_blockjob.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-)
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

Add the migration capability flag and the propagation of the corresponding mapping configuration. The mapping will be produced from the bitmaps on disk depending on both sides of the migration and the necessity to perform merges. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration_params.c | 24 ++++++++++++++++++++++++ src/qemu/qemu_migration_params.h | 5 +++++ 2 files changed, 29 insertions(+) diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c index 510dad783a..8f491e0ed2 100644 --- a/src/qemu/qemu_migration_params.c +++ b/src/qemu/qemu_migration_params.c @@ -63,6 +63,7 @@ struct _qemuMigrationParams { unsigned long long compMethods; /* bit-wise OR of qemuMigrationCompressMethod */ virBitmapPtr caps; qemuMigrationParamValue params[QEMU_MIGRATION_PARAM_LAST]; + virJSONValuePtr blockDirtyBitmapMapping; }; typedef enum { @@ -89,6 +90,7 @@ VIR_ENUM_IMPL(qemuMigrationCapability, "pause-before-switchover", "late-block-activate", "multifd", + "dirty-bitmaps", ); @@ -265,6 +267,7 @@ qemuMigrationParamsFree(qemuMigrationParamsPtr migParams) } virBitmapFree(migParams->caps); + virJSONValueFree(migParams->blockDirtyBitmapMapping); g_free(migParams); } @@ -524,6 +527,20 @@ qemuMigrationParamsSetCompression(virTypedParameterPtr params, } +void +qemuMigrationParamsSetBlockDirtyBitmapMapping(qemuMigrationParamsPtr migParams, + virJSONValuePtr *params) +{ + virJSONValueFree(migParams->blockDirtyBitmapMapping); + migParams->blockDirtyBitmapMapping = g_steal_pointer(params); + + if (migParams->blockDirtyBitmapMapping) + ignore_value(virBitmapSetBit(migParams->caps, QEMU_MIGRATION_CAP_BLOCK_DIRTY_BITMAPS)); + else + ignore_value(virBitmapClearBit(migParams->caps, QEMU_MIGRATION_CAP_BLOCK_DIRTY_BITMAPS)); +} + + qemuMigrationParamsPtr qemuMigrationParamsFromFlags(virTypedParameterPtr params, int nparams, @@ -747,6 +764,12 @@ qemuMigrationParamsToJSON(qemuMigrationParamsPtr migParams) return NULL; } + if (migParams->blockDirtyBitmapMapping && + virJSONValueObjectAppend(params, "block-bitmap-mapping", + migParams->blockDirtyBitmapMapping) < 0) + return NULL; + migParams->blockDirtyBitmapMapping = NULL; + return g_steal_pointer(¶ms); } @@ -1202,6 +1225,7 @@ qemuMigrationParamsReset(virQEMUDriverPtr driver, goto cleanup; qemuMigrationParamsResetTLS(driver, vm, asyncJob, origParams, apiFlags); + /* We don't reset 'block-bitmap-mapping' as it can't be unset */ cleanup: virErrorRestore(&err); diff --git a/src/qemu/qemu_migration_params.h b/src/qemu/qemu_migration_params.h index 9876101bfc..f1db42ce94 100644 --- a/src/qemu/qemu_migration_params.h +++ b/src/qemu/qemu_migration_params.h @@ -39,6 +39,7 @@ typedef enum { QEMU_MIGRATION_CAP_PAUSE_BEFORE_SWITCHOVER, QEMU_MIGRATION_CAP_LATE_BLOCK_ACTIVATE, QEMU_MIGRATION_CAP_MULTIFD, + QEMU_MIGRATION_CAP_BLOCK_DIRTY_BITMAPS, QEMU_MIGRATION_CAP_LAST } qemuMigrationCapability; @@ -132,6 +133,10 @@ qemuMigrationParamsGetULL(qemuMigrationParamsPtr migParams, qemuMigrationParam param, unsigned long long *value); +void +qemuMigrationParamsSetBlockDirtyBitmapMapping(qemuMigrationParamsPtr migParams, + virJSONValuePtr *params); + int qemuMigrationParamsCheck(virQEMUDriverPtr driver, virDomainObjPtr vm, -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:50 +0100, Peter Krempa wrote:
Add the migration capability flag and the propagation of the corresponding mapping configuration. The mapping will be produced from the bitmaps on disk depending on both sides of the migration and the necessity to perform merges.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration_params.c | 24 ++++++++++++++++++++++++ src/qemu/qemu_migration_params.h | 5 +++++ 2 files changed, 29 insertions(+)
diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c index 510dad783a..8f491e0ed2 100644 --- a/src/qemu/qemu_migration_params.c +++ b/src/qemu/qemu_migration_params.c ... @@ -524,6 +527,20 @@ qemuMigrationParamsSetCompression(virTypedParameterPtr params, }
+void +qemuMigrationParamsSetBlockDirtyBitmapMapping(qemuMigrationParamsPtr migParams, + virJSONValuePtr *params) +{ + virJSONValueFree(migParams->blockDirtyBitmapMapping); + migParams->blockDirtyBitmapMapping = g_steal_pointer(params); + + if (migParams->blockDirtyBitmapMapping) + ignore_value(virBitmapSetBit(migParams->caps, QEMU_MIGRATION_CAP_BLOCK_DIRTY_BITMAPS)); + else + ignore_value(virBitmapClearBit(migParams->caps, QEMU_MIGRATION_CAP_BLOCK_DIRTY_BITMAPS)); +} + + qemuMigrationParamsPtr qemuMigrationParamsFromFlags(virTypedParameterPtr params, int nparams, @@ -747,6 +764,12 @@ qemuMigrationParamsToJSON(qemuMigrationParamsPtr migParams) return NULL; }
+ if (migParams->blockDirtyBitmapMapping && + virJSONValueObjectAppend(params, "block-bitmap-mapping", + migParams->blockDirtyBitmapMapping) < 0) + return NULL; + migParams->blockDirtyBitmapMapping = NULL;
I checked all (hopefully) call paths leading to this function and what you're doing is safe, but I still would not expect a function creating json from migParams to eat anything from the source. Especially when the corresponding bit in migParams->caps would remain set. Can we make a copy here instead to avoid (unlikely, though) surprises in the future?
+ return g_steal_pointer(¶ms); }
@@ -1202,6 +1225,7 @@ qemuMigrationParamsReset(virQEMUDriverPtr driver, goto cleanup;
qemuMigrationParamsResetTLS(driver, vm, asyncJob, origParams, apiFlags); + /* We don't reset 'block-bitmap-mapping' as it can't be unset */
So what happens if migration fails? Will mapping be cleared as a side effect of removing the temporary migration bitmaps or will it stay set for future migration? Although I guess the next attempt would either set the appropriate capability and replace the mapping or not set the capability and thus any possibly existing mapping would be ignored in case it was not cleared, right? Jirka

On Wed, Feb 17, 2021 at 10:42:13 +0100, Jiri Denemark wrote:
On Thu, Feb 11, 2021 at 16:37:50 +0100, Peter Krempa wrote:
Add the migration capability flag and the propagation of the corresponding mapping configuration. The mapping will be produced from the bitmaps on disk depending on both sides of the migration and the necessity to perform merges.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration_params.c | 24 ++++++++++++++++++++++++ src/qemu/qemu_migration_params.h | 5 +++++ 2 files changed, 29 insertions(+)
[...]
@@ -1202,6 +1225,7 @@ qemuMigrationParamsReset(virQEMUDriverPtr driver, goto cleanup;
qemuMigrationParamsResetTLS(driver, vm, asyncJob, origParams, apiFlags); + /* We don't reset 'block-bitmap-mapping' as it can't be unset */
So what happens if migration fails? Will mapping be cleared as a side effect of removing the temporary migration bitmaps or will it stay set for future migration? Although I guess the next attempt would either set the appropriate capability and replace the mapping or not set the capability and thus any possibly existing mapping would be ignored in case it was not cleared, right?
Any further migration which wants to enable the 'dirty-bitmaps' migration capability must set it's own mapping. QEMU doesn't have a way to revert to the default mapping once you set it once. It's not a problem for us though, we always want to set the mapping because the default one must be from our side considered always wrong. We don't guarantee that the node names of storage match on the destination side of the migration and the default mapping expects that.

In cases where we are copying the storage we need to ensure that also bitmaps are copied properly. This patch adds migration cookie XML infrastructure which will allow the migration sides reach consensus on which bitmaps to migrate. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration_cookie.c | 134 +++++++++++++++++++++++++++++++ src/qemu/qemu_migration_cookie.h | 34 ++++++++ 2 files changed, 168 insertions(+) diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_cookie.c index 6f2b1b2f57..94ba9c83d0 100644 --- a/src/qemu/qemu_migration_cookie.c +++ b/src/qemu/qemu_migration_cookie.c @@ -51,6 +51,7 @@ VIR_ENUM_IMPL(qemuMigrationCookieFlag, "cpu", "allowReboot", "capabilities", + "block-dirty-bitmaps", ); @@ -116,6 +117,39 @@ qemuMigrationCookieCapsFree(qemuMigrationCookieCapsPtr caps) G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMigrationCookieCaps, qemuMigrationCookieCapsFree); +static void +qemuMigrationBlockDirtyBitmapsDiskBitmapFree(qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bmp) +{ + if (!bmp) + return; + + g_free(bmp->bitmapname); + g_free(bmp->alias); + g_free(bmp->sourcebitmap); + g_free(bmp); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMigrationBlockDirtyBitmapsDiskBitmap, + qemuMigrationBlockDirtyBitmapsDiskBitmapFree); + + +static void +qemuMigrationBlockDirtyBitmapsDiskFree(qemuMigrationBlockDirtyBitmapsDiskPtr dsk) +{ + if (!dsk) + return; + + g_free(dsk->target); + if (dsk->bitmaps) + g_slist_free_full(dsk->bitmaps, + (GDestroyNotify) qemuMigrationBlockDirtyBitmapsDiskBitmapFree); + g_free(dsk); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMigrationBlockDirtyBitmapsDisk, + qemuMigrationBlockDirtyBitmapsDiskFree); + + void qemuMigrationCookieFree(qemuMigrationCookiePtr mig) { @@ -135,6 +169,9 @@ qemuMigrationCookieFree(qemuMigrationCookiePtr mig) g_clear_pointer(&mig->jobInfo, qemuDomainJobInfoFree); virCPUDefFree(mig->cpu); qemuMigrationCookieCapsFree(mig->caps); + if (mig->blockDirtyBitmaps) + g_slist_free_full(mig->blockDirtyBitmaps, + (GDestroyNotify) qemuMigrationBlockDirtyBitmapsDiskFree); g_free(mig); } @@ -758,6 +795,48 @@ qemuMigrationCookieNBDXMLFormat(qemuMigrationCookieNBDPtr nbd, } +static void +qemuMigrationCookieBlockDirtyBitmapsFormat(virBufferPtr buf, + GSList *bitmaps) +{ + g_auto(virBuffer) disksBuf = VIR_BUFFER_INIT_CHILD(buf); + GSList *nextdisk; + + for (nextdisk = bitmaps; nextdisk; nextdisk = nextdisk->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data; + g_auto(virBuffer) diskAttrBuf = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) diskChildBuf = VIR_BUFFER_INIT_CHILD(&disksBuf); + bool hasBitmaps = false; + GSList *nextbitmap; + + if (disk->skip || !disk->bitmaps) + continue; + + for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap = nextbitmap->next) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data; + + if (bitmap->skip) + continue; + + virBufferAsprintf(&diskChildBuf, + "<bitmap name='%s' alias='%s'/>\n", + bitmap->bitmapname, bitmap->alias); + + hasBitmaps = true; + } + + if (!hasBitmaps) + continue; + + virBufferAsprintf(&diskAttrBuf, " target='%s'", disk->target); + virXMLFormatElement(&disksBuf, "disk", &diskAttrBuf, &diskChildBuf); + } + + + virXMLFormatElement(buf, "blockDirtyBitmaps", NULL, &disksBuf); +} + + int qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, virQEMUCapsPtr qemuCaps, @@ -829,6 +908,9 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, if (mig->flags & QEMU_MIGRATION_COOKIE_CAPS) qemuMigrationCookieCapsXMLFormat(buf, mig->caps); + if (mig->flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS) + qemuMigrationCookieBlockDirtyBitmapsFormat(buf, mig->blockDirtyBitmaps); + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</qemu-migration>\n"); return 0; @@ -1132,6 +1214,53 @@ qemuMigrationCookieXMLParseMandatoryFeatures(xmlXPathContextPtr ctxt, } +static int +qemuMigrationCookieBlockDirtyBitmapsParse(xmlXPathContextPtr ctxt, + qemuMigrationCookiePtr mig) +{ + g_autoslist(qemuMigrationBlockDirtyBitmapsDisk) disks = NULL; + g_autofree xmlNodePtr *disknodes = NULL; + int ndisknodes; + size_t i; + VIR_XPATH_NODE_AUTORESTORE(ctxt) + + if ((ndisknodes = virXPathNodeSet("./blockDirtyBitmaps/disk", ctxt, &disknodes)) < 0) + return -1; + + for (i = 0; i < ndisknodes; i++) { + GSList *bitmaps = NULL; + qemuMigrationBlockDirtyBitmapsDiskPtr disk; + g_autofree xmlNodePtr *bitmapnodes = NULL; + int nbitmapnodes; + size_t j; + + ctxt->node = disknodes[i]; + + if ((nbitmapnodes = virXPathNodeSet("./bitmap", ctxt, &bitmapnodes)) < 0) + return -1; + + for (j = 0; j < nbitmapnodes; j++) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap; + + bitmap = g_new0(qemuMigrationBlockDirtyBitmapsDiskBitmap, 1); + bitmap->bitmapname = virXMLPropString(bitmapnodes[j], "name"); + bitmap->alias = virXMLPropString(bitmapnodes[j], "alias"); + bitmaps = g_slist_prepend(bitmaps, bitmap); + } + + disk = g_new0(qemuMigrationBlockDirtyBitmapsDisk, 1); + disk->target = virXMLPropString(disknodes[i], "target"); + disk->bitmaps = g_slist_reverse(bitmaps); + + disks = g_slist_prepend(disks, disk); + } + + mig->blockDirtyBitmaps = g_slist_reverse(g_steal_pointer(&disks)); + + return 0; +} + + static int qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, virQEMUDriverPtr driver, @@ -1275,6 +1404,11 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, !(mig->caps = qemuMigrationCookieCapsXMLParse(ctxt))) return -1; + if (flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS && + virXPathBoolean("boolean(./blockDirtyBitmaps)", ctxt) && + qemuMigrationCookieBlockDirtyBitmapsParse(ctxt, mig) < 0) + return -1; + return 0; } diff --git a/src/qemu/qemu_migration_cookie.h b/src/qemu/qemu_migration_cookie.h index ecd1a01375..8636f955da 100644 --- a/src/qemu/qemu_migration_cookie.h +++ b/src/qemu/qemu_migration_cookie.h @@ -35,6 +35,7 @@ typedef enum { QEMU_MIGRATION_COOKIE_FLAG_CPU, QEMU_MIGRATION_COOKIE_FLAG_ALLOW_REBOOT, QEMU_MIGRATION_COOKIE_FLAG_CAPS, + QEMU_MIGRATION_COOKIE_FLAG_BLOCK_DIRTY_BITMAPS, QEMU_MIGRATION_COOKIE_FLAG_LAST } qemuMigrationCookieFlags; @@ -53,6 +54,7 @@ typedef enum { QEMU_MIGRATION_COOKIE_CPU = (1 << QEMU_MIGRATION_COOKIE_FLAG_CPU), QEMU_MIGRATION_COOKIE_ALLOW_REBOOT = (1 << QEMU_MIGRATION_COOKIE_FLAG_ALLOW_REBOOT), QEMU_MIGRATION_COOKIE_CAPS = (1 << QEMU_MIGRATION_COOKIE_FLAG_CAPS), + QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS = (1 << QEMU_MIGRATION_COOKIE_FLAG_BLOCK_DIRTY_BITMAPS), } qemuMigrationCookieFeatures; typedef struct _qemuMigrationCookieGraphics qemuMigrationCookieGraphics; @@ -107,6 +109,35 @@ struct _qemuMigrationCookieCaps { virBitmapPtr automatic; }; +typedef struct _qemuMigrationBlockDirtyBitmapsDiskBitmap qemuMigrationBlockDirtyBitmapsDiskBitmap; +typedef qemuMigrationBlockDirtyBitmapsDiskBitmap *qemuMigrationBlockDirtyBitmapsDiskBitmapPtr; +struct _qemuMigrationBlockDirtyBitmapsDiskBitmap { + /* config */ + char *bitmapname; + char *alias; + + /* runtime */ + virTristateBool persistent; /* force persisting of the bitmap */ + char *sourcebitmap; /* optional, actual bitmap to migrate in case we needed + to create a temporary one by merging */ + bool skip; /* omit this bitmap */ +}; + + +typedef struct _qemuMigrationBlockDirtyBitmapsDisk qemuMigrationBlockDirtyBitmapsDisk; +typedef qemuMigrationBlockDirtyBitmapsDisk *qemuMigrationBlockDirtyBitmapsDiskPtr; +struct _qemuMigrationBlockDirtyBitmapsDisk { + char *target; + + GSList *bitmaps; + + /* runtime data */ + virDomainDiskDefPtr disk; /* disk object corresponding to 'target' */ + const char *nodename; /* nodename of the top level source of 'disk' */ + bool skip; /* omit this disk */ +}; + + typedef struct _qemuMigrationCookie qemuMigrationCookie; typedef qemuMigrationCookie *qemuMigrationCookiePtr; struct _qemuMigrationCookie { @@ -150,6 +181,9 @@ struct _qemuMigrationCookie { /* If flags & QEMU_MIGRATION_COOKIE_CAPS */ qemuMigrationCookieCapsPtr caps; + + /* If flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS */ + GSList *blockDirtyBitmaps; }; -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:51 +0100, Peter Krempa wrote:
In cases where we are copying the storage we need to ensure that also bitmaps are copied properly. This patch adds migration cookie XML infrastructure which will allow the migration sides reach consensus on which bitmaps to migrate.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration_cookie.c | 134 +++++++++++++++++++++++++++++++ src/qemu/qemu_migration_cookie.h | 34 ++++++++ 2 files changed, 168 insertions(+)
diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_cookie.c index 6f2b1b2f57..94ba9c83d0 100644 --- a/src/qemu/qemu_migration_cookie.c +++ b/src/qemu/qemu_migration_cookie.c ... @@ -758,6 +795,48 @@ qemuMigrationCookieNBDXMLFormat(qemuMigrationCookieNBDPtr nbd, }
+static void +qemuMigrationCookieBlockDirtyBitmapsFormat(virBufferPtr buf, + GSList *bitmaps) +{ + g_auto(virBuffer) disksBuf = VIR_BUFFER_INIT_CHILD(buf); + GSList *nextdisk; + + for (nextdisk = bitmaps; nextdisk; nextdisk = nextdisk->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data; + g_auto(virBuffer) diskAttrBuf = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) diskChildBuf = VIR_BUFFER_INIT_CHILD(&disksBuf); + bool hasBitmaps = false; + GSList *nextbitmap; + + if (disk->skip || !disk->bitmaps) + continue; + + for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap = nextbitmap->next) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data; + + if (bitmap->skip) + continue; + + virBufferAsprintf(&diskChildBuf, + "<bitmap name='%s' alias='%s'/>\n", + bitmap->bitmapname, bitmap->alias); + + hasBitmaps = true; + } + + if (!hasBitmaps) + continue;
You could drop hasBitmaps and call virBufferUse instead, but not a big deal.
+ + virBufferAsprintf(&diskAttrBuf, " target='%s'", disk->target); + virXMLFormatElement(&disksBuf, "disk", &diskAttrBuf, &diskChildBuf); + } + + + virXMLFormatElement(buf, "blockDirtyBitmaps", NULL, &disksBuf); +} + + int qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, virQEMUCapsPtr qemuCaps, @@ -829,6 +908,9 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, if (mig->flags & QEMU_MIGRATION_COOKIE_CAPS) qemuMigrationCookieCapsXMLFormat(buf, mig->caps);
+ if (mig->flags & QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS) + qemuMigrationCookieBlockDirtyBitmapsFormat(buf, mig->blockDirtyBitmaps); + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</qemu-migration>\n"); return 0; @@ -1132,6 +1214,53 @@ qemuMigrationCookieXMLParseMandatoryFeatures(xmlXPathContextPtr ctxt, }
+static int +qemuMigrationCookieBlockDirtyBitmapsParse(xmlXPathContextPtr ctxt, + qemuMigrationCookiePtr mig) +{ + g_autoslist(qemuMigrationBlockDirtyBitmapsDisk) disks = NULL; + g_autofree xmlNodePtr *disknodes = NULL; + int ndisknodes; + size_t i; + VIR_XPATH_NODE_AUTORESTORE(ctxt) + + if ((ndisknodes = virXPathNodeSet("./blockDirtyBitmaps/disk", ctxt, &disknodes)) < 0) + return -1; + + for (i = 0; i < ndisknodes; i++) { + GSList *bitmaps = NULL; + qemuMigrationBlockDirtyBitmapsDiskPtr disk; + g_autofree xmlNodePtr *bitmapnodes = NULL; + int nbitmapnodes; + size_t j; + + ctxt->node = disknodes[i]; + + if ((nbitmapnodes = virXPathNodeSet("./bitmap", ctxt, &bitmapnodes)) < 0) + return -1; + + for (j = 0; j < nbitmapnodes; j++) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap; + + bitmap = g_new0(qemuMigrationBlockDirtyBitmapsDiskBitmap, 1); + bitmap->bitmapname = virXMLPropString(bitmapnodes[j], "name"); + bitmap->alias = virXMLPropString(bitmapnodes[j], "alias");
So what if the attributes do not exist? And virXMLPropString does not abort on OOM. You should check for the result being non-NULL here.
+ bitmaps = g_slist_prepend(bitmaps, bitmap); + } + + disk = g_new0(qemuMigrationBlockDirtyBitmapsDisk, 1); + disk->target = virXMLPropString(disknodes[i], "target");
And here as well.
+ disk->bitmaps = g_slist_reverse(bitmaps); + + disks = g_slist_prepend(disks, disk); + } + + mig->blockDirtyBitmaps = g_slist_reverse(g_steal_pointer(&disks)); + + return 0; +} + + static int qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig, virQEMUDriverPtr driver, ...
With the checks for virXMLPropString result added Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

'qemuMigrationCookieBlockDirtyBitmapsMatchDisks' maps the bitmaps from the migration cookie to actual disk objects definition pointers. 'qemuMigrationCookieBlockDirtyBitmapsToParams' converts the bitmap definitions from the migration cookie into parameters for the 'block-bitmap-mapping' migration parameter. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration_cookie.c | 115 +++++++++++++++++++++++++++++++ src/qemu/qemu_migration_cookie.h | 7 ++ 2 files changed, 122 insertions(+) diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_cookie.c index 94ba9c83d0..ffb7533b6a 100644 --- a/src/qemu/qemu_migration_cookie.c +++ b/src/qemu/qemu_migration_cookie.c @@ -1568,3 +1568,118 @@ qemuMigrationCookieParse(virQEMUDriverPtr driver, return g_steal_pointer(&mig); } + + +/** + * qemuMigrationCookieBlockDirtyBitmapsMatchDisks: + * @def: domain definition + * @disks: list of qemuMigrationBlockDirtyBitmapsDiskPtr + * + * Matches all of the @disks to the actual domain disk definition objects + * by looking up the target. + */ +int +qemuMigrationCookieBlockDirtyBitmapsMatchDisks(virDomainDefPtr def, + GSList *disks) +{ + GSList *next; + + for (next = disks; next; next = next->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = next->data; + + if (!(disk->disk = virDomainDiskByTarget(def, disk->target))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Can't find disk '%s' in domain definition"), + disk->target); + return -1; + } + + disk->nodename = disk->disk->src->nodeformat; + } + + return 0; +} + + +/** + * qemuMigrationCookieBlockDirtyBitmapsToParams: + * @disks: list of qemuMigrationBlockDirtyBitmapsDisk + * @mapping: filled with resulting mapping + * + * Converts @disks into the arguments for 'block-bitmap-mapping' migration + * parameter. + */ +int +qemuMigrationCookieBlockDirtyBitmapsToParams(GSList *disks, + virJSONValuePtr *mapping) +{ + g_autoptr(virJSONValue) map = virJSONValueNewArray(); + bool hasDisks = false; + GSList *nextdisk; + + for (nextdisk = disks; nextdisk; nextdisk = nextdisk->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data; + g_autoptr(virJSONValue) jsondisk = NULL; + g_autoptr(virJSONValue) jsonbitmaps = virJSONValueNewArray(); + bool hasBitmaps = false; + GSList *nextbitmap; + + if (disk->skip || !disk->bitmaps) + continue; + + for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap = nextbitmap->next) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data; + g_autoptr(virJSONValue) jsonbitmap = NULL; + g_autoptr(virJSONValue) transform = NULL; + const char *bitmapname = bitmap->sourcebitmap; + + if (bitmap->skip) + continue; + + /* if there isn't an override, use the real name */ + if (!bitmapname) + bitmapname = bitmap->bitmapname; + + if (bitmap->persistent == VIR_TRISTATE_BOOL_YES) { + if (virJSONValueObjectCreate(&transform, + "b:persistent", true, NULL) < 0) + return -1; + } + + if (virJSONValueObjectCreate(&jsonbitmap, + "s:name", bitmapname, + "s:alias", bitmap->alias, + "A:transform", &transform, + NULL) < 0) + return -1; + + if (virJSONValueArrayAppend(jsonbitmaps, jsonbitmap) < 0) + return -1; + + jsonbitmap = NULL; + hasBitmaps = true; + } + + if (!hasBitmaps) + continue; + + if (virJSONValueObjectCreate(&jsondisk, + "s:node-name", disk->nodename, + "s:alias", disk->target, + "a:bitmaps", &jsonbitmaps, + NULL) < 0) + return -1; + + if (virJSONValueArrayAppend(map, jsondisk) < 0) + return -1; + + jsondisk = NULL; + hasDisks = true; + } + + if (!hasDisks) + return 0; + + *mapping = g_steal_pointer(&map); + return 0; +} diff --git a/src/qemu/qemu_migration_cookie.h b/src/qemu/qemu_migration_cookie.h index 8636f955da..f8393e0ce0 100644 --- a/src/qemu/qemu_migration_cookie.h +++ b/src/qemu/qemu_migration_cookie.h @@ -226,3 +226,10 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, virQEMUCapsPtr qemuCaps, virBufferPtr buf, qemuMigrationCookiePtr mig); + +int qemuMigrationCookieBlockDirtyBitmapsMatchDisks(virDomainDefPtr def, + GSList *disks); + +int +qemuMigrationCookieBlockDirtyBitmapsToParams(GSList *disks, + virJSONValuePtr *mapping); -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:52 +0100, Peter Krempa wrote:
'qemuMigrationCookieBlockDirtyBitmapsMatchDisks' maps the bitmaps from the migration cookie to actual disk objects definition pointers.
'qemuMigrationCookieBlockDirtyBitmapsToParams' converts the bitmap definitions from the migration cookie into parameters for the 'block-bitmap-mapping' migration parameter.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration_cookie.c | 115 +++++++++++++++++++++++++++++++ src/qemu/qemu_migration_cookie.h | 7 ++ 2 files changed, 122 insertions(+) ... diff --git a/src/qemu/qemu_migration_cookie.h b/src/qemu/qemu_migration_cookie.h index 8636f955da..f8393e0ce0 100644 --- a/src/qemu/qemu_migration_cookie.h +++ b/src/qemu/qemu_migration_cookie.h @@ -226,3 +226,10 @@ qemuMigrationCookieXMLFormat(virQEMUDriverPtr driver, virQEMUCapsPtr qemuCaps, virBufferPtr buf, qemuMigrationCookiePtr mig); + +int qemuMigrationCookieBlockDirtyBitmapsMatchDisks(virDomainDefPtr def, + GSList *disks); + +int +qemuMigrationCookieBlockDirtyBitmapsToParams(GSList *disks, + virJSONValuePtr *mapping);
A little bit of consistency would not hurt :-) Either int qemuMigrationCookieBlockDirtyBitmapsMatchDisks(... or int qemuMigrationCookieBlockDirtyBitmapsToParams(... Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

Add status XML infrastructure for storing a list of block dirty bitmaps which are temporarily used when migrating a VM with VIR_MIGRATE_NON_SHARED_DISK for cleanup after a libvirtd restart during migration. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_domain.c | 90 ++++++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_domain.h | 15 +++++++ 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 53b4fb5f4f..ed37917670 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -86,6 +86,18 @@ qemuJobAllocPrivate(void) } +void +qemuDomainJobPrivateMigrateTempBitmapFree(qemuDomainJobPrivateMigrateTempBitmapPtr bmp) +{ + if (!bmp) + return; + + g_free(bmp->nodename); + g_free(bmp->bitmapname); + g_free(bmp); +} + + static void qemuJobFreePrivate(void *opaque) { @@ -95,6 +107,9 @@ qemuJobFreePrivate(void *opaque) return; qemuMigrationParamsFree(priv->migParams); + if (priv->migTempBitmaps) + g_slist_free_full(priv->migTempBitmaps, + (GDestroyNotify) qemuDomainJobPrivateMigrateTempBitmapFree); VIR_FREE(priv); } @@ -165,6 +180,28 @@ qemuDomainObjPrivateXMLFormatNBDMigration(virBufferPtr buf, return 0; } + +static void +qemuDomainObjPrivateXMLFormatMigrationBlockDirtyBitmapsTemp(virBufferPtr buf, + GSList *bitmaps) +{ + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + GSList *next; + + for (next = bitmaps; next; next = next->next) { + qemuDomainJobPrivateMigrateTempBitmapPtr t = next->data; + g_auto(virBuffer) bitmapBuf = VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&bitmapBuf, " name='%s'", t->bitmapname); + virBufferAsprintf(&bitmapBuf, " nodename='%s'", t->nodename); + + virXMLFormatElement(&childBuf, "bitmap", &bitmapBuf, NULL); + } + + virXMLFormatElement(buf, "tempBlockDirtyBitmaps", NULL, &childBuf); +} + + static int qemuDomainFormatJobPrivate(virBufferPtr buf, qemuDomainJobObjPtr job, @@ -172,9 +209,14 @@ qemuDomainFormatJobPrivate(virBufferPtr buf, { qemuDomainJobPrivatePtr priv = job->privateData; - if (job->asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT && - qemuDomainObjPrivateXMLFormatNBDMigration(buf, vm) < 0) - return -1; + if (job->asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) { + if (qemuDomainObjPrivateXMLFormatNBDMigration(buf, vm) < 0) + return -1; + + if (priv->migTempBitmaps) + qemuDomainObjPrivateXMLFormatMigrationBlockDirtyBitmapsTemp(buf, + priv->migTempBitmaps); + } if (priv->migParams) qemuMigrationParamsFormat(buf, priv->migParams); @@ -267,6 +309,45 @@ qemuDomainObjPrivateXMLParseJobNBD(virDomainObjPtr vm, return 0; } + +static int +qemuDomainParseJobPrivateXMLMigrationBlockDirtyBitmapsTemp(qemuDomainJobPrivatePtr jobPriv, + xmlXPathContextPtr ctxt) +{ + g_autoslist(qemuDomainJobPrivateMigrateTempBitmap) bitmaps = NULL; + g_autofree xmlNodePtr *nodes = NULL; + size_t i; + int n; + + if ((n = virXPathNodeSet("./tempBlockDirtyBitmaps/bitmap", ctxt, &nodes)) < 0) + return -1; + + if (n == 0) + return 0; + + for (i = 0; i < n; i++) { + g_autofree char *bitmapname = virXMLPropString(nodes[i], "name"); + g_autofree char *nodename = virXMLPropString(nodes[i], "nodename"); + qemuDomainJobPrivateMigrateTempBitmapPtr bmp; + + if (!bitmapname || !nodename) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed <tempBlockDirtyBitmaps>")); + return -1; + } + + bmp = g_new0(qemuDomainJobPrivateMigrateTempBitmap, 1); + bmp->nodename = g_steal_pointer(&nodename); + bmp->bitmapname = g_steal_pointer(&bitmapname); + + bitmaps = g_slist_prepend(bitmaps, bmp); + } + + jobPriv->migTempBitmaps = g_slist_reverse(g_steal_pointer(&bitmaps)); + return 0; +} + + static int qemuDomainParseJobPrivate(xmlXPathContextPtr ctxt, qemuDomainJobObjPtr job, @@ -277,6 +358,9 @@ qemuDomainParseJobPrivate(xmlXPathContextPtr ctxt, if (qemuDomainObjPrivateXMLParseJobNBD(vm, ctxt) < 0) return -1; + if (qemuDomainParseJobPrivateXMLMigrationBlockDirtyBitmapsTemp(priv, ctxt) < 0) + return -1; + if (qemuMigrationParamsParse(ctxt, &priv->migParams) < 0) return -1; diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 7453881a31..d8ed3aebe4 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -487,6 +487,20 @@ struct _qemuDomainXmlNsDef { char **capsdel; }; + +typedef struct _qemuDomainJobPrivateMigrateTempBitmap qemuDomainJobPrivateMigrateTempBitmap; +typedef qemuDomainJobPrivateMigrateTempBitmap *qemuDomainJobPrivateMigrateTempBitmapPtr; + +struct _qemuDomainJobPrivateMigrateTempBitmap { + char *nodename; + char *bitmapname; +}; + +void +qemuDomainJobPrivateMigrateTempBitmapFree(qemuDomainJobPrivateMigrateTempBitmapPtr bmp); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuDomainJobPrivateMigrateTempBitmap, qemuDomainJobPrivateMigrateTempBitmapFree); + + typedef struct _qemuDomainJobPrivate qemuDomainJobPrivate; typedef qemuDomainJobPrivate *qemuDomainJobPrivatePtr; struct _qemuDomainJobPrivate { @@ -495,6 +509,7 @@ struct _qemuDomainJobPrivate { bool spiceMigrated; /* spice migration completed */ bool dumpCompleted; /* dump completed */ qemuMigrationParamsPtr migParams; + GSList *migTempBitmaps; /* temporary block dirty bitmaps - qemuDomainJobPrivateMigrateTempBitmap */ }; int qemuDomainObjStartWorker(virDomainObjPtr dom); -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:53 +0100, Peter Krempa wrote:
Add status XML infrastructure for storing a list of block dirty bitmaps which are temporarily used when migrating a VM with VIR_MIGRATE_NON_SHARED_DISK for cleanup after a libvirtd restart during migration.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_domain.c | 90 ++++++++++++++++++++++++++++++++++++++++-- src/qemu/qemu_domain.h | 15 +++++++ 2 files changed, 102 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 53b4fb5f4f..ed37917670 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -86,6 +86,18 @@ qemuJobAllocPrivate(void) }
+void +qemuDomainJobPrivateMigrateTempBitmapFree(qemuDomainJobPrivateMigrateTempBitmapPtr bmp) +{ + if (!bmp) + return; + + g_free(bmp->nodename); + g_free(bmp->bitmapname); + g_free(bmp); +} + + static void qemuJobFreePrivate(void *opaque) { @@ -95,6 +107,9 @@ qemuJobFreePrivate(void *opaque) return;
qemuMigrationParamsFree(priv->migParams); + if (priv->migTempBitmaps) + g_slist_free_full(priv->migTempBitmaps, + (GDestroyNotify) qemuDomainJobPrivateMigrateTempBitmapFree);
I just realized this now although the same pattern is used in previous patches... Shouldn't g_slist_free_full be able to cope with NULL making the if () check before it redundant?
VIR_FREE(priv); }
@@ -165,6 +180,28 @@ qemuDomainObjPrivateXMLFormatNBDMigration(virBufferPtr buf, return 0; }
+ +static void +qemuDomainObjPrivateXMLFormatMigrationBlockDirtyBitmapsTemp(virBufferPtr buf, + GSList *bitmaps)
The naming is pretty inconsistent here, how about qemuDomainObjPrivateXMLFormatMigrateTempBitmap(...)?
+{ + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + GSList *next; + + for (next = bitmaps; next; next = next->next) { + qemuDomainJobPrivateMigrateTempBitmapPtr t = next->data; + g_auto(virBuffer) bitmapBuf = VIR_BUFFER_INITIALIZER; + + virBufferAsprintf(&bitmapBuf, " name='%s'", t->bitmapname); + virBufferAsprintf(&bitmapBuf, " nodename='%s'", t->nodename); + + virXMLFormatElement(&childBuf, "bitmap", &bitmapBuf, NULL); + } + + virXMLFormatElement(buf, "tempBlockDirtyBitmaps", NULL, &childBuf); +} + + static int qemuDomainFormatJobPrivate(virBufferPtr buf, qemuDomainJobObjPtr job, @@ -172,9 +209,14 @@ qemuDomainFormatJobPrivate(virBufferPtr buf, { qemuDomainJobPrivatePtr priv = job->privateData;
- if (job->asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT && - qemuDomainObjPrivateXMLFormatNBDMigration(buf, vm) < 0) - return -1; + if (job->asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) { + if (qemuDomainObjPrivateXMLFormatNBDMigration(buf, vm) < 0) + return -1; + + if (priv->migTempBitmaps) + qemuDomainObjPrivateXMLFormatMigrationBlockDirtyBitmapsTemp(buf, + priv->migTempBitmaps);
You could just directly call the formatting function as it won't format anything when priv->migTempBitmaps is an empty list.
+ }
if (priv->migParams) qemuMigrationParamsFormat(buf, priv->migParams); @@ -267,6 +309,45 @@ qemuDomainObjPrivateXMLParseJobNBD(virDomainObjPtr vm, return 0; }
+ +static int +qemuDomainParseJobPrivateXMLMigrationBlockDirtyBitmapsTemp(qemuDomainJobPrivatePtr jobPriv, + xmlXPathContextPtr ctxt)
qemuDomainObjPrivateXMLParseMigrateTempBitmap would make the naming a bit more consistent with other formatting and parsing functions.
+{ + g_autoslist(qemuDomainJobPrivateMigrateTempBitmap) bitmaps = NULL; + g_autofree xmlNodePtr *nodes = NULL; + size_t i; + int n; + + if ((n = virXPathNodeSet("./tempBlockDirtyBitmaps/bitmap", ctxt, &nodes)) < 0) + return -1; + + if (n == 0) + return 0; + + for (i = 0; i < n; i++) { + g_autofree char *bitmapname = virXMLPropString(nodes[i], "name"); + g_autofree char *nodename = virXMLPropString(nodes[i], "nodename"); + qemuDomainJobPrivateMigrateTempBitmapPtr bmp; + + if (!bitmapname || !nodename) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed <tempBlockDirtyBitmaps>")); + return -1; + }
Right, something similar is needed in patch 12/19. Although you could mention extend the error message here and mention the error happened in a status XML. And you could even get away without the temp variables by marking bmp for autoclean and stealing its content when adding to the list.
+ + bmp = g_new0(qemuDomainJobPrivateMigrateTempBitmap, 1); + bmp->nodename = g_steal_pointer(&nodename); + bmp->bitmapname = g_steal_pointer(&bitmapname); + + bitmaps = g_slist_prepend(bitmaps, bmp); + } + + jobPriv->migTempBitmaps = g_slist_reverse(g_steal_pointer(&bitmaps)); + return 0; +} + + static int qemuDomainParseJobPrivate(xmlXPathContextPtr ctxt, qemuDomainJobObjPtr job, @@ -277,6 +358,9 @@ qemuDomainParseJobPrivate(xmlXPathContextPtr ctxt, if (qemuDomainObjPrivateXMLParseJobNBD(vm, ctxt) < 0) return -1;
+ if (qemuDomainParseJobPrivateXMLMigrationBlockDirtyBitmapsTemp(priv, ctxt) < 0) + return -1; + if (qemuMigrationParamsParse(ctxt, &priv->migParams) < 0) return -1;
... No matter whether you decide to change the functions names... Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

The XML sample shows the status XML when migrating with bitmaps including the <tempBlockDirtyBitmaps> element added in previous commit. It will also be used for the migration cookie test. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- .../migration-out-nbd-bitmaps-in.xml | 574 ++++++++++++++++++ .../migration-out-nbd-bitmaps-out.xml | 1 + tests/qemustatusxml2xmltest.c | 1 + 3 files changed, 576 insertions(+) create mode 100644 tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml create mode 120000 tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-out.xml diff --git a/tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml b/tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml new file mode 100644 index 0000000000..b3d24eda98 --- /dev/null +++ b/tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml @@ -0,0 +1,574 @@ +<domstatus state='paused' reason='migration' pid='2458694'> + <monitor path='/var/lib/libvirt/qemu/domain-11-migr/monitor.sock' type='unix'/> + <namespaces> + <mount/> + </namespaces> + <vcpus> + <vcpu id='0' pid='2458745'/> + </vcpus> + <qemuCaps> + <flag name='kvm'/> + <flag name='no-hpet'/> + <flag name='spice'/> + <flag name='hda-duplex'/> + <flag name='ccid-emulated'/> + <flag name='ccid-passthru'/> + <flag name='virtio-tx-alg'/> + <flag name='virtio-blk-pci.ioeventfd'/> + <flag name='sga'/> + <flag name='virtio-blk-pci.event_idx'/> + <flag name='virtio-net-pci.event_idx'/> + <flag name='piix3-usb-uhci'/> + <flag name='piix4-usb-uhci'/> + <flag name='usb-ehci'/> + <flag name='ich9-usb-ehci1'/> + <flag name='vt82c686b-usb-uhci'/> + <flag name='pci-ohci'/> + <flag name='usb-redir'/> + <flag name='usb-hub'/> + <flag name='ich9-ahci'/> + <flag name='no-acpi'/> + <flag name='virtio-blk-pci.scsi'/> + <flag name='scsi-disk.channel'/> + <flag name='scsi-block'/> + <flag name='hda-micro'/> + <flag name='dump-guest-memory'/> + <flag name='nec-usb-xhci'/> + <flag name='lsi'/> + <flag name='virtio-scsi-pci'/> + <flag name='blockio'/> + <flag name='disable-s3'/> + <flag name='disable-s4'/> + <flag name='usb-redir.filter'/> + <flag name='ide-drive.wwn'/> + <flag name='scsi-disk.wwn'/> + <flag name='seccomp-sandbox'/> + <flag name='reboot-timeout'/> + <flag name='vnc'/> + <flag name='qxl'/> + <flag name='VGA'/> + <flag name='cirrus-vga'/> + <flag name='vmware-svga'/> + <flag name='device-video-primary'/> + <flag name='usb-serial'/> + <flag name='nbd-server'/> + <flag name='virtio-rng'/> + <flag name='rng-random'/> + <flag name='rng-egd'/> + <flag name='megasas'/> + <flag name='tpm-passthrough'/> + <flag name='tpm-tis'/> + <flag name='pci-bridge'/> + <flag name='vfio-pci'/> + <flag name='mem-merge'/> + <flag name='drive-discard'/> + <flag name='dmi-to-pci-bridge'/> + <flag name='i440fx-pci-hole64-size'/> + <flag name='q35-pci-hole64-size'/> + <flag name='usb-storage'/> + <flag name='usb-storage.removable'/> + <flag name='virtio-mmio'/> + <flag name='ich9-intel-hda'/> + <flag name='kvm-pit-lost-tick-policy'/> + <flag name='boot-strict'/> + <flag name='pvpanic'/> + <flag name='spice-file-xfer-disable'/> + <flag name='usb-kbd'/> + <flag name='msg-timestamp'/> + <flag name='active-commit'/> + <flag name='change-backing-file'/> + <flag name='memory-backend-ram'/> + <flag name='numa'/> + <flag name='memory-backend-file'/> + <flag name='usb-audio'/> + <flag name='rtc-reset-reinjection'/> + <flag name='splash-timeout'/> + <flag name='iothread'/> + <flag name='migrate-rdma'/> + <flag name='drive-iotune-max'/> + <flag name='VGA.vgamem_mb'/> + <flag name='vmware-svga.vgamem_mb'/> + <flag name='qxl.vgamem_mb'/> + <flag name='pc-dimm'/> + <flag name='machine-vmport-opt'/> + <flag name='aes-key-wrap'/> + <flag name='dea-key-wrap'/> + <flag name='pci-serial'/> + <flag name='vhost-user-multiqueue'/> + <flag name='migration-event'/> + <flag name='gpex-pcihost'/> + <flag name='ioh3420'/> + <flag name='x3130-upstream'/> + <flag name='xio3130-downstream'/> + <flag name='rtl8139'/> + <flag name='e1000'/> + <flag name='virtio-net'/> + <flag name='gic-version'/> + <flag name='incoming-defer'/> + <flag name='virtio-gpu'/> + <flag name='virtio-gpu.virgl'/> + <flag name='virtio-keyboard'/> + <flag name='virtio-mouse'/> + <flag name='virtio-tablet'/> + <flag name='virtio-input-host'/> + <flag name='chardev-file-append'/> + <flag name='ich9-disable-s3'/> + <flag name='ich9-disable-s4'/> + <flag name='vserport-change-event'/> + <flag name='virtio-balloon-pci.deflate-on-oom'/> + <flag name='mptsas1068'/> + <flag name='spice-gl'/> + <flag name='qxl.vram64_size_mb'/> + <flag name='chardev-logfile'/> + <flag name='debug-threads'/> + <flag name='secret'/> + <flag name='pxb'/> + <flag name='pxb-pcie'/> + <flag name='nec-usb-xhci-ports'/> + <flag name='virtio-scsi-pci.iothread'/> + <flag name='name-guest'/> + <flag name='qxl.max_outputs'/> + <flag name='spice-unix'/> + <flag name='drive-detect-zeroes'/> + <flag name='tls-creds-x509'/> + <flag name='intel-iommu'/> + <flag name='smm'/> + <flag name='virtio-pci-disable-legacy'/> + <flag name='query-hotpluggable-cpus'/> + <flag name='virtio-net.rx_queue_size'/> + <flag name='virtio-vga'/> + <flag name='drive-iotune-max-length'/> + <flag name='ivshmem-plain'/> + <flag name='ivshmem-doorbell'/> + <flag name='query-qmp-schema'/> + <flag name='gluster.debug_level'/> + <flag name='vhost-scsi'/> + <flag name='drive-iotune-group'/> + <flag name='query-cpu-model-expansion'/> + <flag name='virtio-net.host_mtu'/> + <flag name='spice-rendernode'/> + <flag name='nvdimm'/> + <flag name='pcie-root-port'/> + <flag name='query-cpu-definitions'/> + <flag name='block-write-threshold'/> + <flag name='query-named-block-nodes'/> + <flag name='cpu-cache'/> + <flag name='qemu-xhci'/> + <flag name='kernel-irqchip'/> + <flag name='kernel-irqchip.split'/> + <flag name='intel-iommu.intremap'/> + <flag name='intel-iommu.caching-mode'/> + <flag name='intel-iommu.eim'/> + <flag name='intel-iommu.device-iotlb'/> + <flag name='virtio.iommu_platform'/> + <flag name='virtio.ats'/> + <flag name='loadparm'/> + <flag name='vnc-multi-servers'/> + <flag name='virtio-net.tx_queue_size'/> + <flag name='chardev-reconnect'/> + <flag name='virtio-gpu.max_outputs'/> + <flag name='virtio-blk.num-queues'/> + <flag name='vmcoreinfo'/> + <flag name='numa.dist'/> + <flag name='disk-share-rw'/> + <flag name='iscsi.password-secret'/> + <flag name='isa-serial'/> + <flag name='dump-completed'/> + <flag name='qcow2-luks'/> + <flag name='pcie-pci-bridge'/> + <flag name='seccomp-blacklist'/> + <flag name='query-cpus-fast'/> + <flag name='disk-write-cache'/> + <flag name='nbd-tls'/> + <flag name='tpm-crb'/> + <flag name='pr-manager-helper'/> + <flag name='qom-list-properties'/> + <flag name='memory-backend-file.discard-data'/> + <flag name='sdl-gl'/> + <flag name='screendump_device'/> + <flag name='hda-output'/> + <flag name='blockdev-del'/> + <flag name='vmgenid'/> + <flag name='vhost-vsock'/> + <flag name='chardev-fd-pass'/> + <flag name='tpm-emulator'/> + <flag name='mch'/> + <flag name='mch.extended-tseg-mbytes'/> + <flag name='usb-storage.werror'/> + <flag name='egl-headless'/> + <flag name='vfio-pci.display'/> + <flag name='blockdev'/> + <flag name='memory-backend-memfd'/> + <flag name='memory-backend-memfd.hugetlb'/> + <flag name='iothread.poll-max-ns'/> + <flag name='egl-headless.rendernode'/> + <flag name='memory-backend-file.align'/> + <flag name='memory-backend-file.pmem'/> + <flag name='nvdimm.unarmed'/> + <flag name='scsi-disk.device_id'/> + <flag name='virtio-pci-non-transitional'/> + <flag name='overcommit'/> + <flag name='query-current-machine'/> + <flag name='bitmap-merge'/> + <flag name='nbd-bitmap'/> + <flag name='x86-max-cpu'/> + <flag name='cpu-unavailable-features'/> + <flag name='canonical-cpu-features'/> + <flag name='bochs-display'/> + <flag name='migration-file-drop-cache'/> + <flag name='dbus-vmstate'/> + <flag name='vhost-user-gpu'/> + <flag name='vhost-user-vga'/> + <flag name='incremental-backup'/> + <flag name='ramfb'/> + <flag name='blockdev-file-dynamic-auto-read-only'/> + <flag name='savevm-monitor-nodes'/> + <flag name='drive-nvme'/> + <flag name='smp-dies'/> + <flag name='i8042'/> + <flag name='rng-builtin'/> + <flag name='virtio-net.failover'/> + <flag name='vhost-user-fs'/> + <flag name='query-named-block-nodes.flat'/> + <flag name='blockdev-snapshot.allow-write-only-overlay'/> + <flag name='blockdev-reopen'/> + <flag name='storage.werror'/> + <flag name='fsdev.multidevs'/> + <flag name='virtio.packed'/> + <flag name='pcie-root-port.hotplug'/> + <flag name='aio.io_uring'/> + <flag name='tcg'/> + <flag name='virtio-blk-pci.scsi.default.disabled'/> + <flag name='pvscsi'/> + <flag name='cpu.migratable'/> + <flag name='query-cpu-model-expansion.migratable'/> + <flag name='fw_cfg'/> + <flag name='migration-param.bandwidth'/> + <flag name='migration-param.downtime'/> + <flag name='migration-param.xbzrle-cache-size'/> + <flag name='intel-iommu.aw-bits'/> + <flag name='numa.hmat'/> + <flag name='blockdev-hostdev-scsi'/> + <flag name='usb-host.hostdevice'/> + <flag name='virtio-balloon.free-page-reporting'/> + <flag name='block-export-add'/> + <flag name='netdev.vhost-vdpa'/> + <flag name='fsdev.createmode'/> + <flag name='dc390'/> + <flag name='am53c974'/> + <flag name='virtio-pmem-pci'/> + <flag name='vhost-user-fs.bootindex'/> + <flag name='vhost-user-blk'/> + <flag name='cpu-max'/> + <flag name='migration-param.block-bitmap-mapping'/> + </qemuCaps> + <job type='none' async='migration out' phase='perform3' flags='0x42'> + <disk dev='hda' migrating='no'/> + <disk dev='vda' migrating='yes'> + <migrationSource type='network' format='raw'> + <source protocol='nbd' name='drive-virtio-disk0' tlsFromConfig='0'> + <host name='migr' port='49153'/> + <privateData> + <nodenames> + <nodename type='storage' name='migration-vda-storage'/> + <nodename type='format' name='migration-vda-format'/> + </nodenames> + </privateData> + </source> + </migrationSource> + </disk> + <tempBlockDirtyBitmaps> + <bitmap name='libvirt-migration-libvirt-vda-c' nodename='libvirt-1-format'/> + <bitmap name='libvirt-migration-libvirt-vda-b' nodename='libvirt-1-format'/> + <bitmap name='libvirt-migration-libvirt-vda-a' nodename='libvirt-1-format'/> + </tempBlockDirtyBitmaps> + <migParams> + <param name='compress-level' value='1'/> + <param name='compress-threads' value='8'/> + <param name='decompress-threads' value='2'/> + <param name='cpu-throttle-initial' value='20'/> + <param name='cpu-throttle-increment' value='10'/> + <param name='tls-creds' value=''/> + <param name='tls-hostname' value=''/> + <param name='max-bandwidth' value='134217728'/> + <param name='downtime-limit' value='300'/> + <param name='block-incremental' value='no'/> + <param name='xbzrle-cache-size' value='67108864'/> + <param name='max-postcopy-bandwidth' value='0'/> + <param name='multifd-channels' value='2'/> + </migParams> + </job> + <devices> + <device alias='sound0'/> + <device alias='sata1'/> + <device alias='ide0-0-0'/> + <device alias='video0'/> + <device alias='redir1'/> + <device alias='serial0'/> + <device alias='balloon0'/> + <device alias='sata0'/> + <device alias='usb'/> + <device alias='scsi0'/> + <device alias='redir0'/> + <device alias='channel1'/> + <device alias='virtio-disk0'/> + <device alias='sound0-codec0'/> + <device alias='channel0'/> + <device alias='virtio-serial0'/> + <device alias='input0'/> + <device alias='rng0'/> + </devices> + <libDir path='/var/lib/libvirt/qemu/domain-11-migr'/> + <channelTargetDir path='/var/lib/libvirt/qemu/channel/target/domain-11-migr'/> + <cpu mode='custom' match='exact' check='partial'> + <model fallback='forbid'>EPYC-Rome</model> + <vendor>AMD</vendor> + <feature policy='require' name='x2apic'/> + <feature policy='require' name='tsc-deadline'/> + <feature policy='require' name='hypervisor'/> + <feature policy='require' name='tsc_adjust'/> + <feature policy='require' name='stibp'/> + <feature policy='require' name='arch-capabilities'/> + <feature policy='require' name='ssbd'/> + <feature policy='require' name='xsaves'/> + <feature policy='require' name='cmp_legacy'/> + <feature policy='require' name='amd-ssbd'/> + <feature policy='require' name='virt-ssbd'/> + <feature policy='require' name='rdctl-no'/> + <feature policy='require' name='skip-l1dfl-vmentry'/> + <feature policy='require' name='mds-no'/> + <feature policy='require' name='pschange-mc-no'/> + </cpu> + <chardevStdioLogd/> + <rememberOwner/> + <allowReboot value='yes'/> + <nodename index='3'/> + <blockjobs active='yes'> + <blockjob name='drive-virtio-disk0' type='copy' state='ready' jobflags='0x0'> + <disk dst='vda'/> + </blockjob> + </blockjobs> + <agentTimeout>-2</agentTimeout> + <domain type='kvm' id='11'> + <name>migr</name> + <uuid>10b01607-0323-486b-afe2-3014a8a5b98b</uuid> + <memory unit='KiB'>1024000</memory> + <currentMemory unit='KiB'>1024000</currentMemory> + <vcpu placement='static'>1</vcpu> + <resource> + <partition>/machine</partition> + </resource> + <os> + <type arch='x86_64' machine='pc-i440fx-2.9'>hvm</type> + <bootmenu enable='yes'/> + </os> + <features> + <acpi/> + <apic/> + <vmport state='off'/> + </features> + <cpu mode='custom' match='exact' check='full'> + <model fallback='forbid'>EPYC-Rome</model> + <vendor>AMD</vendor> + <feature policy='require' name='x2apic'/> + <feature policy='require' name='tsc-deadline'/> + <feature policy='require' name='hypervisor'/> + <feature policy='require' name='tsc_adjust'/> + <feature policy='require' name='stibp'/> + <feature policy='require' name='arch-capabilities'/> + <feature policy='require' name='ssbd'/> + <feature policy='require' name='xsaves'/> + <feature policy='require' name='cmp_legacy'/> + <feature policy='require' name='amd-ssbd'/> + <feature policy='require' name='virt-ssbd'/> + <feature policy='require' name='rdctl-no'/> + <feature policy='require' name='skip-l1dfl-vmentry'/> + <feature policy='require' name='mds-no'/> + <feature policy='require' name='pschange-mc-no'/> + <feature policy='disable' name='svm'/> + <feature policy='disable' name='npt'/> + <feature policy='disable' name='nrip-save'/> + </cpu> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <pm> + <suspend-to-mem enabled='no'/> + <suspend-to-disk enabled='no'/> + </pm> + <devices> + <emulator>/home/pipo/git/qemu.git/build/x86_64-softmmu/qemu-system-x86_64</emulator> + <disk type='file' device='cdrom'> + <driver name='qemu' type='raw'/> + <source file='/var/lib/libvirt/images/systemrescuecd-amd64-6.1.2.iso' index='2'> + <privateData> + <nodenames> + <nodename type='storage' name='libvirt-2-storage'/> + <nodename type='format' name='libvirt-2-format'/> + </nodenames> + </privateData> + </source> + <backingStore/> + <target dev='hda' bus='ide'/> + <readonly/> + <boot order='1'/> + <alias name='ide0-0-0'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + <privateData> + <qom name='ide0-0-0'/> + </privateData> + </disk> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2'/> + <source file='/tmp/migr.qcow2' index='1'> + <privateData> + <nodenames> + <nodename type='storage' name='libvirt-1-storage'/> + <nodename type='format' name='libvirt-1-format'/> + </nodenames> + </privateData> + </source> + <backingStore type='file' index='3'> + <format type='qcow2'/> + <source file='/tmp/migr-base.qcow2'> + <privateData> + <nodenames> + <nodename type='storage' name='libvirt-3-storage'/> + <nodename type='format' name='libvirt-3-format'/> + </nodenames> + </privateData> + </source> + <backingStore/> + </backingStore> + <target dev='vda' bus='virtio'/> + <alias name='virtio-disk0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + <privateData> + <qom name='/machine/peripheral/virtio-disk0/virtio-backend'/> + </privateData> + </disk> + <controller type='usb' index='0' model='ich9-ehci1'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x7'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci1'> + <alias name='usb'/> + <master startport='0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0' multifunction='on'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci2'> + <alias name='usb'/> + <master startport='2'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x1'/> + </controller> + <controller type='usb' index='0' model='ich9-uhci3'> + <alias name='usb'/> + <master startport='4'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'> + <alias name='pci.0'/> + </controller> + <controller type='virtio-serial' index='0'> + <alias name='virtio-serial0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='ide' index='0'> + <alias name='ide'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <alias name='scsi0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <alias name='sata0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </controller> + <controller type='sata' index='1'> + <alias name='sata1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='fdc' index='0'> + <alias name='fdc0'/> + </controller> + <serial type='pty'> + <source path='/dev/pts/47'/> + <target type='isa-serial' port='0'> + <model name='isa-serial'/> + </target> + <alias name='serial0'/> + </serial> + <console type='pty' tty='/dev/pts/47'> + <source path='/dev/pts/47'/> + <target type='serial' port='0'/> + <alias name='serial0'/> + </console> + <channel type='unix'> + <source mode='bind' path='/var/lib/libvirt/qemu/channel/target/domain-11-migr/org.qemu.guest_agent.0'/> + <target type='virtio' name='org.qemu.guest_agent.0' state='disconnected'/> + <alias name='channel0'/> + <address type='virtio-serial' controller='0' bus='0' port='1'/> + </channel> + <channel type='spicevmc'> + <target type='virtio' name='com.redhat.spice.0' state='disconnected'/> + <alias name='channel1'/> + <address type='virtio-serial' controller='0' bus='0' port='2'/> + </channel> + <input type='tablet' bus='usb'> + <alias name='input0'/> + <address type='usb' bus='0' port='1'/> + </input> + <input type='mouse' bus='ps2'> + <alias name='input1'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input2'/> + </input> + <graphics type='spice' port='5902' autoport='yes' listen='127.0.0.1'> + <listen type='address' address='127.0.0.1' fromConfig='1' autoGenerated='no'/> + <image compression='off'/> + <gl enable='no'/> + </graphics> + <sound model='ich6'> + <alias name='sound0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </sound> + <video> + <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/> + <alias name='video0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </video> + <redirdev bus='usb' type='spicevmc'> + <alias name='redir0'/> + <address type='usb' bus='0' port='2'/> + </redirdev> + <redirdev bus='usb' type='spicevmc'> + <alias name='redir1'/> + <address type='usb' bus='0' port='3'/> + </redirdev> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </memballoon> + <rng model='virtio'> + <backend model='random'>/dev/random</backend> + <alias name='rng0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </rng> + </devices> + <seclabel type='dynamic' model='selinux' relabel='yes'> + <label>unconfined_u:unconfined_r:svirt_t:s0:c38,c915</label> + <imagelabel>unconfined_u:object_r:svirt_image_t:s0:c38,c915</imagelabel> + </seclabel> + <seclabel type='dynamic' model='dac' relabel='yes'> + <label>+107:+107</label> + <imagelabel>+107:+107</imagelabel> + </seclabel> + </domain> +</domstatus> diff --git a/tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-out.xml b/tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-out.xml new file mode 120000 index 0000000000..a3d38478d5 --- /dev/null +++ b/tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-out.xml @@ -0,0 +1 @@ +migration-out-nbd-bitmaps-in.xml \ No newline at end of file diff --git a/tests/qemustatusxml2xmltest.c b/tests/qemustatusxml2xmltest.c index 67a070c986..39be0edf69 100644 --- a/tests/qemustatusxml2xmltest.c +++ b/tests/qemustatusxml2xmltest.c @@ -133,6 +133,7 @@ mymain(void) DO_TEST_STATUS("migration-in-params"); DO_TEST_STATUS("migration-out-params"); DO_TEST_STATUS("migration-out-nbd-tls"); + DO_TEST_STATUS("migration-out-nbd-bitmaps"); DO_TEST_STATUS("upgrade"); DO_TEST_STATUS("blockjob-blockdev"); -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:54 +0100, Peter Krempa wrote:
The XML sample shows the status XML when migrating with bitmaps including the <tempBlockDirtyBitmaps> element added in previous commit.
It will also be used for the migration cookie test.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- .../migration-out-nbd-bitmaps-in.xml | 574 ++++++++++++++++++ .../migration-out-nbd-bitmaps-out.xml | 1 + tests/qemustatusxml2xmltest.c | 1 + 3 files changed, 576 insertions(+) create mode 100644 tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml create mode 120000 tests/qemustatusxml2xmldata/migration-out-nbd-bitmaps-out.xml
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

Test the XML infrastructure for <blockDirtyBitmaps> migration cookie element as well as the conversion to migration parameters for QMP schema validation. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- tests/meson.build | 2 +- .../nbd-bitmaps-xml2xml-in.xml | 52 ++++++ .../nbd-bitmaps-xml2xml-migparams.json | 25 +++ .../nbd-bitmaps-xml2xml-out.xml | 51 ++++++ tests/qemumigrationcookiexmltest.c | 166 +++++++++++++++--- 5 files changed, 269 insertions(+), 27 deletions(-) create mode 100644 tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-in.xml create mode 100644 tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-migparams.json create mode 100644 tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-out.xml diff --git a/tests/meson.build b/tests/meson.build index 0de0783839..b9b2255666 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -452,7 +452,7 @@ if conf.has('WITH_QEMU') { 'name': 'qemuhotplugtest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemumemlocktest', 'link_with': [ test_qemu_driver_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemumigparamstest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, - { 'name': 'qemumigrationcookiexmltest', 'link_with': [ test_qemu_driver_lib ], 'link_whole': [ test_utils_qemu_lib, test_file_wrapper_lib ] }, + { 'name': 'qemumigrationcookiexmltest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib, test_file_wrapper_lib ] }, { 'name': 'qemumonitorjsontest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemusecuritytest', 'sources': [ 'qemusecuritytest.c', 'qemusecuritymock.c' ], 'link_with': [ test_qemu_driver_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemustatusxml2xmltest', 'link_with': [ test_qemu_driver_lib ], 'link_whole': [ test_utils_qemu_lib, test_file_wrapper_lib ] }, diff --git a/tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-in.xml b/tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-in.xml new file mode 100644 index 0000000000..b219c25f27 --- /dev/null +++ b/tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-in.xml @@ -0,0 +1,52 @@ +<qemu-migration> + <name>migr</name> + <uuid>10b01607-0323-486b-afe2-3014a8a5b98b</uuid> + <hostname>sourcehost</hostname> + <hostuuid>1f5e0da0-fecf-413f-9bf1-1aa9c21e71e4</hostuuid> + <feature name='lockstate'/> + <nbd> + <disk target='hda' capacity='708837376'/> + <disk target='vda' capacity='10485760'/> + </nbd> + <cpu mode='custom' match='exact' check='full'> + <model fallback='forbid'>EPYC-Rome</model> + <vendor>AMD</vendor> + <feature policy='require' name='x2apic'/> + <feature policy='require' name='tsc-deadline'/> + <feature policy='require' name='hypervisor'/> + <feature policy='require' name='tsc_adjust'/> + <feature policy='require' name='stibp'/> + <feature policy='require' name='arch-capabilities'/> + <feature policy='require' name='ssbd'/> + <feature policy='require' name='xsaves'/> + <feature policy='require' name='cmp_legacy'/> + <feature policy='require' name='amd-ssbd'/> + <feature policy='require' name='virt-ssbd'/> + <feature policy='require' name='rdctl-no'/> + <feature policy='require' name='skip-l1dfl-vmentry'/> + <feature policy='require' name='mds-no'/> + <feature policy='require' name='pschange-mc-no'/> + <feature policy='disable' name='svm'/> + <feature policy='disable' name='npt'/> + <feature policy='disable' name='nrip-save'/> + </cpu> + <allowReboot value='yes'/> + <capabilities> + <cap name='xbzrle' auto='no'/> + <cap name='auto-converge' auto='no'/> + <cap name='rdma-pin-all' auto='no'/> + <cap name='postcopy-ram' auto='no'/> + <cap name='compress' auto='no'/> + <cap name='pause-before-switchover' auto='yes'/> + <cap name='late-block-activate' auto='no'/> + <cap name='multifd' auto='no'/> + <cap name='dirty-bitmaps' auto='no'/> + </capabilities> + <blockDirtyBitmaps> + <disk target='vda'> + <bitmap name='a' alias='libvirt-vda-a'/> + <bitmap name='b' alias='libvirt-vda-b'/> + <bitmap name='c' alias='libvirt-vda-c'/> + </disk> + </blockDirtyBitmaps> +</qemu-migration> diff --git a/tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-migparams.json b/tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-migparams.json new file mode 100644 index 0000000000..100da7c270 --- /dev/null +++ b/tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-migparams.json @@ -0,0 +1,25 @@ +{ + "block-bitmap-mapping": [ + { + "node-name": "libvirt-1-format", + "alias": "vda", + "bitmaps": [ + { + "name": "a", + "alias": "libvirt-vda-a", + "transform": { + "persistent": true + } + }, + { + "name": "b", + "alias": "libvirt-vda-b" + }, + { + "name": "c", + "alias": "libvirt-vda-c" + } + ] + } + ] +} diff --git a/tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-out.xml b/tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-out.xml new file mode 100644 index 0000000000..09b6fa291c --- /dev/null +++ b/tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-out.xml @@ -0,0 +1,51 @@ +<qemu-migration> + <name>migr</name> + <uuid>10b01607-0323-486b-afe2-3014a8a5b98b</uuid> + <hostname>hostname</hostname> + <hostuuid>4a802f00-4cba-5df6-9679-a08c4c5b577f</hostuuid> + <nbd> + <disk target='hda' capacity='708837376'/> + <disk target='vda' capacity='10485760'/> + </nbd> + <cpu mode='custom' match='exact' check='full'> + <model fallback='forbid'>EPYC-Rome</model> + <vendor>AMD</vendor> + <feature policy='require' name='x2apic'/> + <feature policy='require' name='tsc-deadline'/> + <feature policy='require' name='hypervisor'/> + <feature policy='require' name='tsc_adjust'/> + <feature policy='require' name='stibp'/> + <feature policy='require' name='arch-capabilities'/> + <feature policy='require' name='ssbd'/> + <feature policy='require' name='xsaves'/> + <feature policy='require' name='cmp_legacy'/> + <feature policy='require' name='amd-ssbd'/> + <feature policy='require' name='virt-ssbd'/> + <feature policy='require' name='rdctl-no'/> + <feature policy='require' name='skip-l1dfl-vmentry'/> + <feature policy='require' name='mds-no'/> + <feature policy='require' name='pschange-mc-no'/> + <feature policy='disable' name='svm'/> + <feature policy='disable' name='npt'/> + <feature policy='disable' name='nrip-save'/> + </cpu> + <allowReboot value='yes'/> + <capabilities> + <cap name='xbzrle' auto='no'/> + <cap name='auto-converge' auto='no'/> + <cap name='rdma-pin-all' auto='no'/> + <cap name='postcopy-ram' auto='no'/> + <cap name='compress' auto='no'/> + <cap name='pause-before-switchover' auto='yes'/> + <cap name='late-block-activate' auto='no'/> + <cap name='multifd' auto='no'/> + <cap name='dirty-bitmaps' auto='no'/> + </capabilities> + <blockDirtyBitmaps> + <disk target='vda'> + <bitmap name='a' alias='libvirt-vda-a'/> + <bitmap name='b' alias='libvirt-vda-b'/> + <bitmap name='c' alias='libvirt-vda-c'/> + </disk> + </blockDirtyBitmaps> +</qemu-migration> diff --git a/tests/qemumigrationcookiexmltest.c b/tests/qemumigrationcookiexmltest.c index 5fe0ba8a8a..7f2437a7fe 100644 --- a/tests/qemumigrationcookiexmltest.c +++ b/tests/qemumigrationcookiexmltest.c @@ -25,9 +25,13 @@ #include "internal.h" #include "testutilsqemu.h" +#include "testutilsqemuschema.h" #include "configmake.h" +#define LIBVIRT_QEMU_MIGRATION_PARAMSPRIV_H_ALLOW + #include "qemu/qemu_migration_cookie.h" +#include "qemu/qemu_migration_paramspriv.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -61,13 +65,33 @@ struct testQemuMigrationCookieData { qemuMigrationParty cookiePopulateParty; + qemuMigrationCookiePtr cookie; + char *xmlstr; int xmlstrlen; char *infile; char *outfile; + char *outmigparamsfile; }; +static void +testQemuMigrationCookieDataFree(struct testQemuMigrationCookieData *data) +{ + if (!data) + return; + + qemuMigrationCookieFree(data->cookie); + g_free(data->xmlstr); + g_free(data->outfile); + g_free(data->infile); + g_free(data->outmigparamsfile); + g_free(data->inStatus); + virDomainObjEndAPI(&data->vm); + g_free(data); +} + + static int testQemuMigrationCookiePopulate(const void *opaque) { @@ -115,26 +139,25 @@ testQemuMigrationCookieParse(const void *opaque) struct testQemuMigrationCookieData *data = (struct testQemuMigrationCookieData *) opaque; qemuDomainObjPrivatePtr priv = data->vm->privateData; g_auto(virBuffer) actual = VIR_BUFFER_INITIALIZER; - g_autoptr(qemuMigrationCookie) cookie = NULL; - if (!(cookie = qemuMigrationCookieParse(&driver, - data->vm->def, - NULL, - priv, - data->xmlstr, - data->xmlstrlen, - data->cookieParseFlags))) { + if (!(data->cookie = qemuMigrationCookieParse(&driver, + data->vm->def, + NULL, + priv, + data->xmlstr, + data->xmlstrlen, + data->cookieParseFlags))) { VIR_TEST_DEBUG("\nfailed to parse qemu migration cookie:\n%s\n", data->xmlstr); return -1; } /* set all flags so that formatter attempts to format everything */ - cookie->flags = ~0; + data->cookie->flags = ~0; if (qemuMigrationCookieXMLFormat(&driver, priv->qemuCaps, &actual, - cookie) < 0) { + data->cookie) < 0) { VIR_TEST_DEBUG("\nfailed to format back qemu migration cookie"); return -1; } @@ -179,21 +202,6 @@ testQemuMigrationCookieXMLLoad(const void *opaque) } -static void -testQemuMigrationCookieDataFree(struct testQemuMigrationCookieData *data) -{ - if (!data) - return; - - g_free(data->xmlstr); - g_free(data->outfile); - g_free(data->infile); - g_free(data->inStatus); - virDomainObjEndAPI(&data->vm); - g_free(data); -} - - static int testQemuMigrationCookieDom2XML(const char *namesuffix, const char *domxml, @@ -207,9 +215,11 @@ testQemuMigrationCookieDom2XML(const char *namesuffix, /* flags unsupported by default: * - lockstate: internals are NULL in tests, causes crash * - nbd: monitor not present + * - dirty bitmaps: monitor not present */ unsigned int cookiePopulateFlagMask = QEMU_MIGRATION_COOKIE_LOCKSTATE | - QEMU_MIGRATION_COOKIE_NBD; + QEMU_MIGRATION_COOKIE_NBD | + QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS; data->cookiePopulateFlags = ~cookiePopulateFlagMask; } @@ -286,6 +296,107 @@ testQemuMigrationCookieXML2XML(const char *name, } +static int +testQemuMigrationCookieBlockDirtyBitmaps(const void *opaque) +{ + const struct testQemuMigrationCookieData *data = opaque; + g_autoptr(virJSONValue) migParamsBitmaps = NULL; + g_autofree char *actualJSON = NULL; + g_autoptr(virJSONValue) paramsOut = NULL; + g_auto(virBuffer) debug = VIR_BUFFER_INITIALIZER; + g_autoptr(qemuMigrationParams) migParams = NULL; + g_autoptr(GHashTable) qmpschema = NULL; + GSList *next; + + if (!(qmpschema = testQEMUSchemaLoadLatest("x86_64"))) { + VIR_TEST_VERBOSE("failed to load QMP schema"); + return -1; + } + + if (qemuMigrationCookieBlockDirtyBitmapsMatchDisks(data->vm->def, + data->cookie->blockDirtyBitmaps) < 0) + return -1; + + for (next = data->cookie->blockDirtyBitmaps; next; next = next->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = next->data; + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = disk->bitmaps->data; + + bitmap->persistent = VIR_TRISTATE_BOOL_YES; + } + + if (qemuMigrationCookieBlockDirtyBitmapsToParams(data->cookie->blockDirtyBitmaps, + &migParamsBitmaps)) + return -1; + + if (!(migParams = qemuMigrationParamsNew())) + return -1; + + qemuMigrationParamsSetBlockDirtyBitmapMapping(migParams, &migParamsBitmaps); + + if (!(paramsOut = qemuMigrationParamsToJSON(migParams)) || + !(actualJSON = virJSONValueToString(paramsOut, true))) + return -1; + + if (testQEMUSchemaValidateCommand("migrate-set-parameters", + paramsOut, + qmpschema, + false, + false, + &debug) < 0) { + VIR_TEST_VERBOSE("failed to validate migration params '%s' against QMP schema: %s", + actualJSON, virBufferCurrentContent(&debug)); + return -1; + } + + if (virTestCompareToFile(actualJSON, data->outmigparamsfile) < 0) + return -1; + + return 0; +} + + +/* tests also the conversion to list of migrated bitmaps */ +static int +testQemuMigrationCookieXML2XMLBitmaps(const char *name, + const char *statusxml, + unsigned int cookieParseFlags) +{ + struct testQemuMigrationCookieData *data = g_new0(struct testQemuMigrationCookieData, 1); + int ret = 0; + + if (cookieParseFlags == 0) + data->cookieParseFlags = ~0; + + data->inStatus = g_strconcat(abs_srcdir, "/", statusxml, NULL); + data->infile = g_strconcat(abs_srcdir, "/qemumigrationcookiexmldata/", + name, "-xml2xml-in.xml", NULL); + data->outfile = g_strconcat(abs_srcdir, "/qemumigrationcookiexmldata/", + name, "-xml2xml-out.xml", NULL); + data->outmigparamsfile = g_strconcat(abs_srcdir, "/qemumigrationcookiexmldata/", + name, "-xml2xml-migparams.json", NULL); + + if (virTestRun(tn("qemumigrationcookieXML2XML-dom-", name, NULL), + testQemuMigrationCookieDomInit, data) < 0) + ret = -1; + + if (virTestRun(tn("qemumigrationcookieXML2XML-load-", name, NULL), + testQemuMigrationCookieXMLLoad, data) < 0) + ret = -1; + + if (virTestRun(tn("qemumigrationcookieXML2XML-parse-", name, NULL), + testQemuMigrationCookieParse, data) < 0) + ret = -1; + + if (virTestRun(tn("qemumigrationcookieXML2XML-migparams-", name, NULL), + testQemuMigrationCookieBlockDirtyBitmaps, data) < 0) + ret = -1; + + testQemuMigrationCookieDataFree(data); + + return ret; +} + + static int mymain(void) { @@ -321,6 +432,9 @@ mymain(void) testQemuMigrationCookieXML2XML("full", "qemustatusxml2xmldata/modern-in.xml", 0) < 0) ret = -1; + if (testQemuMigrationCookieXML2XMLBitmaps("nbd-bitmaps", "qemustatusxml2xmldata/migration-out-nbd-bitmaps-in.xml", 0) < 0) + ret = -1; + virBufferFreeAndReset(&testnamebuf); cleanup: -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:55 +0100, Peter Krempa wrote:
Test the XML infrastructure for <blockDirtyBitmaps> migration cookie element as well as the conversion to migration parameters for QMP schema validation.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- tests/meson.build | 2 +- .../nbd-bitmaps-xml2xml-in.xml | 52 ++++++ .../nbd-bitmaps-xml2xml-migparams.json | 25 +++ .../nbd-bitmaps-xml2xml-out.xml | 51 ++++++ tests/qemumigrationcookiexmltest.c | 166 +++++++++++++++--- 5 files changed, 269 insertions(+), 27 deletions(-) create mode 100644 tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-in.xml create mode 100644 tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-migparams.json create mode 100644 tests/qemumigrationcookiexmldata/nbd-bitmaps-xml2xml-out.xml
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

In case when the block migration job required temporary bitmaps for merging the appropriate checkpoints we need to clean them up when cancelling the job. On success we don't need to do that though as the bitmaps are just temporary thus are not written to disk. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 37f0d43d24..36424f8493 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -834,6 +834,32 @@ qemuMigrationSrcNBDCopyCancel(virQEMUDriverPtr driver, } +static int +qemuMigrationSrcCancelRemoveTempBitmaps(virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + virQEMUDriverPtr driver = priv->driver; + qemuDomainJobPrivatePtr jobPriv = priv->job.privateData; + GSList *next; + + if (!jobPriv->migTempBitmaps) + return 0; + + for (next = jobPriv->migTempBitmaps; next; next = next->next) { + qemuDomainJobPrivateMigrateTempBitmapPtr t = next->data; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) + return -1; + qemuMonitorBitmapRemove(priv->mon, t->nodename, t->bitmapname); + if (qemuDomainObjExitMonitor(driver, vm) < 0) + return -1; + } + + return 0; +} + + static virStorageSourcePtr qemuMigrationSrcNBDStorageCopyBlockdevPrepareSource(virDomainDiskDefPtr disk, const char *host, @@ -3999,6 +4025,8 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver, QEMU_ASYNC_JOB_MIGRATION_OUT, dconn); + qemuMigrationSrcCancelRemoveTempBitmaps(vm, QEMU_ASYNC_JOB_MIGRATION_OUT); + if (priv->job.current->status != QEMU_DOMAIN_JOB_STATUS_CANCELED) priv->job.current->status = QEMU_DOMAIN_JOB_STATUS_FAILED; } @@ -5701,6 +5729,9 @@ qemuMigrationSrcCancel(virQEMUDriverPtr driver, QEMU_ASYNC_JOB_NONE, NULL) < 0) return -1; + if (qemuMigrationSrcCancelRemoveTempBitmaps(vm, QEMU_ASYNC_JOB_NONE) < 0) + return -1; + return 0; } -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:56 +0100, Peter Krempa wrote:
In case when the block migration job required temporary bitmaps for merging the appropriate checkpoints we need to clean them up when cancelling the job. On success we don't need to do that though as the bitmaps are just temporary thus are not written to disk.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 37f0d43d24..36424f8493 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -834,6 +834,32 @@ qemuMigrationSrcNBDCopyCancel(virQEMUDriverPtr driver, }
+static int +qemuMigrationSrcCancelRemoveTempBitmaps(virDomainObjPtr vm, + qemuDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + virQEMUDriverPtr driver = priv->driver; + qemuDomainJobPrivatePtr jobPriv = priv->job.privateData; + GSList *next; + + if (!jobPriv->migTempBitmaps) + return 0;
This check is pretty much redundant as the loop will do exactly the same.
+ + for (next = jobPriv->migTempBitmaps; next; next = next->next) { + qemuDomainJobPrivateMigrateTempBitmapPtr t = next->data; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) + return -1; + qemuMonitorBitmapRemove(priv->mon, t->nodename, t->bitmapname); + if (qemuDomainObjExitMonitor(driver, vm) < 0) + return -1; + } + + return 0; +} + + static virStorageSourcePtr qemuMigrationSrcNBDStorageCopyBlockdevPrepareSource(virDomainDiskDefPtr disk, const char *host, ...
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

Preserve block dirty bitmaps after migration with QEMU_MONITOR_MIGRATE_NON_SHARED_(DISK|INC). This patch implements functions which offer the bitmaps to the destination, check for eligibility on destination and then configure source for the migration. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 333 +++++++++++++++++++++++++++++++++++++- 1 file changed, 331 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 36424f8493..16bfad0390 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2203,6 +2203,91 @@ qemuMigrationSrcCleanup(virDomainObjPtr vm, } +/** + * qemuMigrationSrcBeginPhaseBlockDirtyBitmaps: + * @mig: migration cookie struct + * @vm: domain object + * @migrate_disks: disks which are being migrated + * @nmigrage_disks: number of @migrate_disks + * + * Enumerates block dirty bitmaps on disks which will undergo storage migration + * and fills them into @mig to be offered to the destination. + */ +static int +qemuMigrationSrcBeginPhaseBlockDirtyBitmaps(qemuMigrationCookiePtr mig, + virDomainObjPtr vm, + const char **migrate_disks, + size_t nmigrate_disks) + +{ + GSList *disks = NULL; + qemuDomainObjPrivatePtr priv = vm->privateData; + size_t i; + + g_autoptr(GHashTable) blockNamedNodeData = NULL; + + if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, priv->job.asyncJob))) + return -1; + + for (i = 0; i < vm->def->ndisks; i++) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk; + GSList *bitmaps = NULL; + virDomainDiskDefPtr diskdef = vm->def->disks[i]; + qemuBlockNamedNodeDataPtr nodedata = virHashLookup(blockNamedNodeData, diskdef->src->nodeformat); + size_t j; + + if (!nodedata) + continue; + + if (migrate_disks) { + bool migrating = false; + + for (j = 0; j < nmigrate_disks; j++) { + if (STREQ(migrate_disks[j], diskdef->dst)) { + migrating = true; + break; + } + } + + if (!migrating) + continue; + } + + for (j = 0; j < nodedata->nbitmaps; j++) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap; + + if (!qemuBlockBitmapChainIsValid(diskdef->src, + nodedata->bitmaps[j]->name, + blockNamedNodeData)) + continue; + + bitmap = g_new0(qemuMigrationBlockDirtyBitmapsDiskBitmap, 1); + bitmap->bitmapname = g_strdup(nodedata->bitmaps[j]->name); + bitmap->alias = g_strdup_printf("libvirt-%s-%s", + diskdef->dst, + nodedata->bitmaps[j]->name); + bitmaps = g_slist_prepend(bitmaps, bitmap); + } + + if (!bitmaps) + continue; + + disk = g_new0(qemuMigrationBlockDirtyBitmapsDisk, 1); + disk->target = g_strdup(diskdef->dst); + disk->bitmaps = bitmaps; + disks = g_slist_prepend(disks, disk); + } + + if (!disks) + return 0; + + mig->blockDirtyBitmaps = disks; + mig->flags |= QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS; + + return 0; +} + + /* The caller is supposed to lock the vm and start a migration job. */ static char * qemuMigrationSrcBeginPhase(virQEMUDriverPtr driver, @@ -2315,6 +2400,12 @@ qemuMigrationSrcBeginPhase(virQEMUDriverPtr driver, if (!(mig = qemuMigrationCookieNew(vm->def, priv->origname))) return NULL; + if (cookieFlags & QEMU_MIGRATION_COOKIE_NBD && + virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_INCREMENTAL_BACKUP) && + qemuMigrationSrcBeginPhaseBlockDirtyBitmaps(mig, vm, migrate_disks, + nmigrate_disks) < 0) + return NULL; + if (qemuMigrationCookieFormat(mig, driver, vm, QEMU_MIGRATION_SOURCE, cookieout, cookieoutlen, @@ -2528,6 +2619,92 @@ qemuMigrationDstPrepare(virDomainObjPtr vm, migrateFrom, fd, NULL); } + +/** + * qemuMigrationDstPrepareAnyBlockDirtyBitmaps: + * @vm: domain object + * @mig: migration cookie + * @migParams: migration parameters + * @flags: migration flags + * + * Checks whether block dirty bitmaps offered by the migration source are + * to be migrated (e.g. they don't exist, the destination is compatible etc) + * and sets up destination qemu for migrating the bitmaps as well as updates the + * list of eligible bitmaps in the migration cookie to be sent back to the + * source. + */ +static int +qemuMigrationDstPrepareAnyBlockDirtyBitmaps(virDomainObjPtr vm, + qemuMigrationCookiePtr mig, + qemuMigrationParamsPtr migParams, + unsigned int flags) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + g_autoptr(virJSONValue) mapping = NULL; + g_autoptr(GHashTable) blockNamedNodeData = NULL; + GSList *nextdisk; + + if (!mig->nbd || + !mig->blockDirtyBitmaps || + !(flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC)) || + !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING)) + return 0; + + if (qemuMigrationCookieBlockDirtyBitmapsMatchDisks(vm->def, mig->blockDirtyBitmaps) < 0) + return -1; + + if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_MIGRATION_IN))) + return -1; + + for (nextdisk = mig->blockDirtyBitmaps; nextdisk; nextdisk = nextdisk->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data; + qemuBlockNamedNodeDataPtr nodedata; + GSList *nextbitmap; + + if (!(nodedata = virHashLookup(blockNamedNodeData, disk->nodename))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find data for block node '%s'"), + disk->nodename); + return -1; + } + + /* don't migrate bitmaps into non-qcow2v3+ images */ + if (disk->disk->src->format != VIR_STORAGE_FILE_QCOW2 || + nodedata->qcow2v2) { + disk->skip = true; + continue; + } + + for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap = nextbitmap->next) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data; + size_t k; + + /* don't migrate into existing bitmaps */ + for (k = 0; k < nodedata->nbitmaps; k++) { + if (STREQ(bitmap->bitmapname, nodedata->bitmaps[k]->name)) { + bitmap->skip = true; + break; + } + } + + if (bitmap->skip) + continue; + } + } + + if (qemuMigrationCookieBlockDirtyBitmapsToParams(mig->blockDirtyBitmaps, + &mapping) < 0) + return -1; + + if (!mapping) + return 0; + + qemuMigrationParamsSetBlockDirtyBitmapMapping(migParams, &mapping); + mig->flags |= QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS; + return 0; +} + + static int qemuMigrationDstPrepareAny(virQEMUDriverPtr driver, virConnectPtr dconn, @@ -2677,7 +2854,8 @@ qemuMigrationDstPrepareAny(virQEMUDriverPtr driver, QEMU_MIGRATION_COOKIE_CPU_HOTPLUG | QEMU_MIGRATION_COOKIE_CPU | QEMU_MIGRATION_COOKIE_ALLOW_REBOOT | - QEMU_MIGRATION_COOKIE_CAPS))) + QEMU_MIGRATION_COOKIE_CAPS | + QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS))) goto cleanup; if (!(vm = virDomainObjListAdd(driver->domains, *def, @@ -2770,6 +2948,9 @@ qemuMigrationDstPrepareAny(virQEMUDriverPtr driver, goto stopjob; } + if (qemuMigrationDstPrepareAnyBlockDirtyBitmaps(vm, mig, migParams, flags) < 0) + goto stopjob; + if (qemuMigrationParamsCheck(driver, vm, QEMU_ASYNC_JOB_MIGRATION_IN, migParams, mig->caps->automatic) < 0) goto stopjob; @@ -3653,6 +3834,145 @@ qemuMigrationSetDBusVMState(virQEMUDriverPtr driver, } +/** + * qemuMigrationSrcRunPrepareBlockDirtyBitmapsMerge: + * @vm: domain object + * @mig: migration cookie + * + * When migrating full disks, which means that the backing chain of the disk + * will be squashed into a single image we need to calculate bitmaps + * corresponding to the checkpoints which express the same set of changes + * for migration. + * + * This function prepares temporary bitmaps and corresponding merges, updates + * the data so that the temporary bitmaps are used and registers the temporary + * bitmaps for deletion on failed migration. + */ +static int +qemuMigrationSrcRunPrepareBlockDirtyBitmapsMerge(virDomainObjPtr vm, + qemuMigrationCookiePtr mig) +{ + g_autoslist(qemuDomainJobPrivateMigrateTempBitmap) tmpbitmaps = NULL; + qemuDomainObjPrivatePtr priv = vm->privateData; + qemuDomainJobPrivatePtr jobPriv = priv->job.privateData; + virQEMUDriverPtr driver = priv->driver; + g_autoptr(virJSONValue) actions = virJSONValueNewArray(); + g_autoptr(GHashTable) blockNamedNodeData = NULL; + GSList *nextdisk; + int rc; + + if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))) + return -1; + + for (nextdisk = mig->blockDirtyBitmaps; nextdisk; nextdisk = nextdisk->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data; + GSList *nextbitmap; + + /* if a disk doesn't have a backing chain we don't need the code below */ + if (!virStorageSourceHasBacking(disk->disk->src)) + continue; + + for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap = nextbitmap->next) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data; + qemuDomainJobPrivateMigrateTempBitmapPtr tmpbmp; + virStorageSourcePtr n; + unsigned long long granularity = 0; + g_autoptr(virJSONValue) merge = virJSONValueNewArray(); + + for (n = disk->disk->src; virStorageSourceIsBacking(n); n = n->backingStore) { + qemuBlockNamedNodeDataBitmapPtr b; + + if (!(b = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData, n, + bitmap->bitmapname))) + break; + + if (granularity == 0) + granularity = b->granularity; + + if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(merge, + n->nodeformat, + b->name) < 0) + return -1; + } + + bitmap->sourcebitmap = g_strdup_printf("libvirt-migration-%s", bitmap->alias); + bitmap->persistent = VIR_TRISTATE_BOOL_YES; + + if (qemuMonitorTransactionBitmapAdd(actions, + disk->disk->src->nodeformat, + bitmap->sourcebitmap, + false, false, granularity) < 0) + return -1; + + if (qemuMonitorTransactionBitmapMerge(actions, + disk->disk->src->nodeformat, + bitmap->sourcebitmap, + &merge) < 0) + return -1; + + tmpbmp = g_new0(qemuDomainJobPrivateMigrateTempBitmap, 1); + tmpbmp->nodename = g_strdup(disk->disk->src->nodeformat); + tmpbmp->bitmapname = g_strdup(bitmap->sourcebitmap); + tmpbitmaps = g_slist_prepend(tmpbitmaps, tmpbmp); + } + } + + if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + return -1; + + rc = qemuMonitorTransaction(priv->mon, &actions); + + if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0) + return -1; + + jobPriv->migTempBitmaps = g_steal_pointer(&tmpbitmaps); + + return 0; +} + + +/** + * qemuMigrationSrcRunPrepareBlockDirtyBitmaps: + * @vm: domain object + * @mig: migration cookie + * @migParams: migration parameters + * @flags: migration flags + * + * Configures the source for bitmap migration when the destination asks + * for bitmaps. + */ +static int +qemuMigrationSrcRunPrepareBlockDirtyBitmaps(virDomainObjPtr vm, + qemuMigrationCookiePtr mig, + qemuMigrationParamsPtr migParams, + unsigned int flags) + +{ + g_autoptr(virJSONValue) mapping = NULL; + + if (!mig->blockDirtyBitmaps) + return 0; + + if (qemuMigrationCookieBlockDirtyBitmapsMatchDisks(vm->def, mig->blockDirtyBitmaps) < 0) + return -1; + + /* For QEMU_MONITOR_MIGRATE_NON_SHARED_INC we can migrate the bitmaps + * directly, otherwise we must create merged bitmaps from the whole + * chain */ + + if (!(flags & QEMU_MONITOR_MIGRATE_NON_SHARED_INC) && + qemuMigrationSrcRunPrepareBlockDirtyBitmapsMerge(vm, mig)) + return -1; + + if (qemuMigrationCookieBlockDirtyBitmapsToParams(mig->blockDirtyBitmaps, + &mapping) < 0) + return -1; + + qemuMigrationParamsSetBlockDirtyBitmapMapping(migParams, &mapping); + return 0; +} + + static int qemuMigrationSrcRun(virQEMUDriverPtr driver, virDomainObjPtr vm, @@ -3709,6 +4029,10 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver, cookieFlags |= QEMU_MIGRATION_COOKIE_NBD; } + if (cookieFlags & QEMU_MIGRATION_COOKIE_NBD && + virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING)) + cookieFlags |= QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS; + if (virLockManagerPluginUsesState(driver->lockManager) && !cookieout) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -3741,13 +4065,18 @@ qemuMigrationSrcRun(virQEMUDriverPtr driver, cookiein, cookieinlen, cookieFlags | QEMU_MIGRATION_COOKIE_GRAPHICS | - QEMU_MIGRATION_COOKIE_CAPS); + QEMU_MIGRATION_COOKIE_CAPS | + QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS); if (!mig) goto error; if (qemuMigrationSrcGraphicsRelocate(driver, vm, mig, graphicsuri) < 0) VIR_WARN("unable to provide data for graphics client relocation"); + if (mig->blockDirtyBitmaps && + qemuMigrationSrcRunPrepareBlockDirtyBitmaps(vm, mig, migParams, flags) < 0) + goto error; + if (qemuMigrationParamsCheck(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT, migParams, mig->caps->automatic) < 0) goto error; -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:57 +0100, Peter Krempa wrote:
Preserve block dirty bitmaps after migration with QEMU_MONITOR_MIGRATE_NON_SHARED_(DISK|INC).
This patch implements functions which offer the bitmaps to the destination, check for eligibility on destination and then configure source for the migration.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 333 +++++++++++++++++++++++++++++++++++++- 1 file changed, 331 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 36424f8493..16bfad0390 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c ... @@ -2528,6 +2619,92 @@ qemuMigrationDstPrepare(virDomainObjPtr vm, migrateFrom, fd, NULL); }
+ +/** + * qemuMigrationDstPrepareAnyBlockDirtyBitmaps: + * @vm: domain object + * @mig: migration cookie + * @migParams: migration parameters + * @flags: migration flags + * + * Checks whether block dirty bitmaps offered by the migration source are + * to be migrated (e.g. they don't exist, the destination is compatible etc) + * and sets up destination qemu for migrating the bitmaps as well as updates the + * list of eligible bitmaps in the migration cookie to be sent back to the + * source. + */ +static int +qemuMigrationDstPrepareAnyBlockDirtyBitmaps(virDomainObjPtr vm, + qemuMigrationCookiePtr mig, + qemuMigrationParamsPtr migParams, + unsigned int flags) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + g_autoptr(virJSONValue) mapping = NULL; + g_autoptr(GHashTable) blockNamedNodeData = NULL; + GSList *nextdisk; + + if (!mig->nbd || + !mig->blockDirtyBitmaps || + !(flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC)) || + !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING)) + return 0;
Shouldn't we report an error in case the source sent bitmaps, but local QEMU does not support QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING?
+ + if (qemuMigrationCookieBlockDirtyBitmapsMatchDisks(vm->def, mig->blockDirtyBitmaps) < 0) + return -1; + + if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_MIGRATION_IN))) + return -1; + + for (nextdisk = mig->blockDirtyBitmaps; nextdisk; nextdisk = nextdisk->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data; + qemuBlockNamedNodeDataPtr nodedata; + GSList *nextbitmap; + + if (!(nodedata = virHashLookup(blockNamedNodeData, disk->nodename))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find data for block node '%s'"), + disk->nodename); + return -1; + } + + /* don't migrate bitmaps into non-qcow2v3+ images */
How about "Bitmaps can only be migrated to qcow2 v3+"?
+ if (disk->disk->src->format != VIR_STORAGE_FILE_QCOW2 || + nodedata->qcow2v2) { + disk->skip = true;
Is skipping the disk the right thing to do? Should we report an error and abort migration instead? Just checking, maybe we can't do so for backward compatibility...
+ continue; + } + + for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap = nextbitmap->next) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data; + size_t k; + + /* don't migrate into existing bitmaps */ + for (k = 0; k < nodedata->nbitmaps; k++) { + if (STREQ(bitmap->bitmapname, nodedata->bitmaps[k]->name)) { + bitmap->skip = true;
And similar questions for bitmaps here.
+ break; + } + } + + if (bitmap->skip) + continue; + } + } + + if (qemuMigrationCookieBlockDirtyBitmapsToParams(mig->blockDirtyBitmaps, + &mapping) < 0) + return -1; + + if (!mapping) + return 0; + + qemuMigrationParamsSetBlockDirtyBitmapMapping(migParams, &mapping); + mig->flags |= QEMU_MIGRATION_COOKIE_BLOCK_DIRTY_BITMAPS; + return 0; +} + + static int qemuMigrationDstPrepareAny(virQEMUDriverPtr driver, virConnectPtr dconn, ... +static int +qemuMigrationSrcRunPrepareBlockDirtyBitmaps(virDomainObjPtr vm, + qemuMigrationCookiePtr mig, + qemuMigrationParamsPtr migParams, + unsigned int flags) + +{ + g_autoptr(virJSONValue) mapping = NULL; + + if (!mig->blockDirtyBitmaps) + return 0; + + if (qemuMigrationCookieBlockDirtyBitmapsMatchDisks(vm->def, mig->blockDirtyBitmaps) < 0) + return -1; + + /* For QEMU_MONITOR_MIGRATE_NON_SHARED_INC we can migrate the bitmaps + * directly, otherwise we must create merged bitmaps from the whole + * chain */ + + if (!(flags & QEMU_MONITOR_MIGRATE_NON_SHARED_INC) && + qemuMigrationSrcRunPrepareBlockDirtyBitmapsMerge(vm, mig))
"< 0" is missing in the check.
+ return -1; + + if (qemuMigrationCookieBlockDirtyBitmapsToParams(mig->blockDirtyBitmaps, + &mapping) < 0) + return -1; + + qemuMigrationParamsSetBlockDirtyBitmapMapping(migParams, &mapping); + return 0; +} + + static int qemuMigrationSrcRun(virQEMUDriverPtr driver, virDomainObjPtr vm,
Jirka

On Thu, Feb 18, 2021 at 15:54:37 +0100, Jiri Denemark wrote:
On Thu, Feb 11, 2021 at 16:37:57 +0100, Peter Krempa wrote:
Preserve block dirty bitmaps after migration with QEMU_MONITOR_MIGRATE_NON_SHARED_(DISK|INC).
This patch implements functions which offer the bitmaps to the destination, check for eligibility on destination and then configure source for the migration.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 333 +++++++++++++++++++++++++++++++++++++- 1 file changed, 331 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 36424f8493..16bfad0390 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c ... @@ -2528,6 +2619,92 @@ qemuMigrationDstPrepare(virDomainObjPtr vm, migrateFrom, fd, NULL); }
+ +/** + * qemuMigrationDstPrepareAnyBlockDirtyBitmaps: + * @vm: domain object + * @mig: migration cookie + * @migParams: migration parameters + * @flags: migration flags + * + * Checks whether block dirty bitmaps offered by the migration source are + * to be migrated (e.g. they don't exist, the destination is compatible etc) + * and sets up destination qemu for migrating the bitmaps as well as updates the + * list of eligible bitmaps in the migration cookie to be sent back to the + * source. + */ +static int +qemuMigrationDstPrepareAnyBlockDirtyBitmaps(virDomainObjPtr vm, + qemuMigrationCookiePtr mig, + qemuMigrationParamsPtr migParams, + unsigned int flags) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + g_autoptr(virJSONValue) mapping = NULL; + g_autoptr(GHashTable) blockNamedNodeData = NULL; + GSList *nextdisk; + + if (!mig->nbd || + !mig->blockDirtyBitmaps || + !(flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC)) || + !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING)) + return 0;
Shouldn't we report an error in case the source sent bitmaps, but local QEMU does not support QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING?
See below.
+ + if (qemuMigrationCookieBlockDirtyBitmapsMatchDisks(vm->def, mig->blockDirtyBitmaps) < 0) + return -1; + + if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_MIGRATION_IN))) + return -1; + + for (nextdisk = mig->blockDirtyBitmaps; nextdisk; nextdisk = nextdisk->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data; + qemuBlockNamedNodeDataPtr nodedata; + GSList *nextbitmap; + + if (!(nodedata = virHashLookup(blockNamedNodeData, disk->nodename))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find data for block node '%s'"), + disk->nodename); + return -1; + } + + /* don't migrate bitmaps into non-qcow2v3+ images */
How about "Bitmaps can only be migrated to qcow2 v3+"?
+ if (disk->disk->src->format != VIR_STORAGE_FILE_QCOW2 || + nodedata->qcow2v2) { + disk->skip = true;
Is skipping the disk the right thing to do? Should we report an error and abort migration instead? Just checking, maybe we can't do so for backward compatibility...
+ continue; + } + + for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap = nextbitmap->next) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data; + size_t k; + + /* don't migrate into existing bitmaps */ + for (k = 0; k < nodedata->nbitmaps; k++) { + if (STREQ(bitmap->bitmapname, nodedata->bitmaps[k]->name)) { + bitmap->skip = true;
And similar questions for bitmaps here.
That would require that we have the users explicitly enable this feature rather than doing it implicitly. The disk format can be changed during the migration. If we want to do it explicitly only I'll need to add a migration flag and all the infra for it.

On Thu, Feb 18, 2021 at 16:50:43 +0100, Peter Krempa wrote:
On Thu, Feb 18, 2021 at 15:54:37 +0100, Jiri Denemark wrote:
On Thu, Feb 11, 2021 at 16:37:57 +0100, Peter Krempa wrote:
Preserve block dirty bitmaps after migration with QEMU_MONITOR_MIGRATE_NON_SHARED_(DISK|INC).
This patch implements functions which offer the bitmaps to the destination, check for eligibility on destination and then configure source for the migration.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_migration.c | 333 +++++++++++++++++++++++++++++++++++++- 1 file changed, 331 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 36424f8493..16bfad0390 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c ... @@ -2528,6 +2619,92 @@ qemuMigrationDstPrepare(virDomainObjPtr vm, migrateFrom, fd, NULL); }
+ +/** + * qemuMigrationDstPrepareAnyBlockDirtyBitmaps: + * @vm: domain object + * @mig: migration cookie + * @migParams: migration parameters + * @flags: migration flags + * + * Checks whether block dirty bitmaps offered by the migration source are + * to be migrated (e.g. they don't exist, the destination is compatible etc) + * and sets up destination qemu for migrating the bitmaps as well as updates the + * list of eligible bitmaps in the migration cookie to be sent back to the + * source. + */ +static int +qemuMigrationDstPrepareAnyBlockDirtyBitmaps(virDomainObjPtr vm, + qemuMigrationCookiePtr mig, + qemuMigrationParamsPtr migParams, + unsigned int flags) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + g_autoptr(virJSONValue) mapping = NULL; + g_autoptr(GHashTable) blockNamedNodeData = NULL; + GSList *nextdisk; + + if (!mig->nbd || + !mig->blockDirtyBitmaps || + !(flags & (VIR_MIGRATE_NON_SHARED_DISK | VIR_MIGRATE_NON_SHARED_INC)) || + !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING)) + return 0;
Shouldn't we report an error in case the source sent bitmaps, but local QEMU does not support QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING?
See below.
+ + if (qemuMigrationCookieBlockDirtyBitmapsMatchDisks(vm->def, mig->blockDirtyBitmaps) < 0) + return -1; + + if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_MIGRATION_IN))) + return -1; + + for (nextdisk = mig->blockDirtyBitmaps; nextdisk; nextdisk = nextdisk->next) { + qemuMigrationBlockDirtyBitmapsDiskPtr disk = nextdisk->data; + qemuBlockNamedNodeDataPtr nodedata; + GSList *nextbitmap; + + if (!(nodedata = virHashLookup(blockNamedNodeData, disk->nodename))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to find data for block node '%s'"), + disk->nodename); + return -1; + } + + /* don't migrate bitmaps into non-qcow2v3+ images */
How about "Bitmaps can only be migrated to qcow2 v3+"?
+ if (disk->disk->src->format != VIR_STORAGE_FILE_QCOW2 || + nodedata->qcow2v2) { + disk->skip = true;
Is skipping the disk the right thing to do? Should we report an error and abort migration instead? Just checking, maybe we can't do so for backward compatibility...
+ continue; + } + + for (nextbitmap = disk->bitmaps; nextbitmap; nextbitmap = nextbitmap->next) { + qemuMigrationBlockDirtyBitmapsDiskBitmapPtr bitmap = nextbitmap->data; + size_t k; + + /* don't migrate into existing bitmaps */ + for (k = 0; k < nodedata->nbitmaps; k++) { + if (STREQ(bitmap->bitmapname, nodedata->bitmaps[k]->name)) { + bitmap->skip = true;
And similar questions for bitmaps here.
That would require that we have the users explicitly enable this feature rather than doing it implicitly. The disk format can be changed during the migration.
If we want to do it explicitly only I'll need to add a migration flag and all the infra for it.
I see. I agree copying the bitmaps whenever possible is a good idea. Reviewed-by: Jiri Denemark <jdenemar@redhat.com>

For incremental backup we need QEMU_CAPS_BLOCKDEV, QEMU_CAPS_BLOCKDEV_REOPEN, QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_capabilities.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 38555dde98..7cc2532954 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -5164,8 +5164,10 @@ virQEMUCapsInitQMPVersionCaps(virQEMUCapsPtr qemuCaps) void virQEMUCapsInitProcessCapsInterlock(virQEMUCapsPtr qemuCaps) { - if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) - virQEMUCapsClear(qemuCaps, QEMU_CAPS_INCREMENTAL_BACKUP); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING)) + virQEMUCapsSet(qemuCaps, QEMU_CAPS_INCREMENTAL_BACKUP); if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE) && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_STORAGE_WERROR)) { -- 2.29.2

On Thu, Feb 11, 2021 at 16:37:58 +0100, Peter Krempa wrote:
For incremental backup we need QEMU_CAPS_BLOCKDEV, QEMU_CAPS_BLOCKDEV_REOPEN, QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_capabilities.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 38555dde98..7cc2532954 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -5164,8 +5164,10 @@ virQEMUCapsInitQMPVersionCaps(virQEMUCapsPtr qemuCaps) void virQEMUCapsInitProcessCapsInterlock(virQEMUCapsPtr qemuCaps) { - if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) - virQEMUCapsClear(qemuCaps, QEMU_CAPS_INCREMENTAL_BACKUP); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN) && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_MIGRATION_PARAM_BLOCK_BITMAP_MAPPING)) + virQEMUCapsSet(qemuCaps, QEMU_CAPS_INCREMENTAL_BACKUP);
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE) && !virQEMUCapsGet(qemuCaps, QEMU_CAPS_USB_STORAGE_WERROR)) {
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
participants (3)
-
Daniel P. Berrangé
-
Jiri Denemark
-
Peter Krempa