diff --git a/SOURCES/kvm-Add-skip_dump-flag-to-ignore-memory-region-during-du.patch b/SOURCES/kvm-Add-skip_dump-flag-to-ignore-memory-region-during-du.patch new file mode 100644 index 0000000..f1c86ce --- /dev/null +++ b/SOURCES/kvm-Add-skip_dump-flag-to-ignore-memory-region-during-du.patch @@ -0,0 +1,129 @@ +From 0ae4c882404b4590c34bb9b03a86f9389413fd1c Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Wed, 7 Sep 2016 14:09:52 +0200 +Subject: [PATCH 2/2] Add skip_dump flag to ignore memory region during dump + +RH-Author: Alex Williamson +Message-id: <20160907140817.21968.47551.stgit@gimli.home> +Patchwork-id: 72264 +O-Subject: [RHEL7.3 qemu-kvm PATCH v2] Add skip_dump flag to ignore memory region during dump +Bugzilla: 1373088 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Auger Eric +RH-Acked-by: Laszlo Ersek + +From: Nikunj A Dadhania + +Bugzilla: 1373088 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=11713365 +Upstream: e4dc3f5909ab90520bc1a27b381c3017ff65ed68 + +The PCI MMIO might be disabled or the device in the reset state. +Make sure we do not dump these memory regions. + +Signed-off-by: Nikunj A Dadhania +Acked-by: Alex Williamson +CC: Paolo Bonzini +Signed-off-by: Paolo Bonzini +Signed-off-by: Miroslav Rezanina +--- + hw/misc/vfio.c | 1 + + include/exec/memory.h | 19 +++++++++++++++++++ + memory.c | 10 ++++++++++ + memory_mapping.c | 3 ++- + 4 files changed, 32 insertions(+), 1 deletion(-) + +diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c +index 36b9832..4fdc09a 100644 +--- a/hw/misc/vfio.c ++++ b/hw/misc/vfio.c +@@ -2596,6 +2596,7 @@ static int vfio_mmap_bar(VFIOBAR *bar, MemoryRegion *mem, MemoryRegion *submem, + } + + memory_region_init_ram_ptr(submem, name, size, *map); ++ memory_region_set_skip_dump(submem); + } else { + empty_region: + /* Create a zero sized sub-region to make cleanup easy. */ +diff --git a/include/exec/memory.h b/include/exec/memory.h +index 3bbe378..448d501 100644 +--- a/include/exec/memory.h ++++ b/include/exec/memory.h +@@ -126,6 +126,7 @@ struct MemoryRegion { + bool terminates; + bool romd_mode; + bool ram; ++ bool skip_dump; + bool readonly; /* For RAM regions */ + bool enabled; + bool rom_device; +@@ -353,6 +354,24 @@ uint64_t memory_region_size(MemoryRegion *mr); + bool memory_region_is_ram(MemoryRegion *mr); + + /** ++ * memory_region_is_skip_dump: check whether a memory region should not be ++ * dumped ++ * ++ * Returns %true is a memory region should not be dumped(e.g. VFIO BAR MMAP). ++ * ++ * @mr: the memory region being queried ++ */ ++bool memory_region_is_skip_dump(MemoryRegion *mr); ++ ++/** ++ * memory_region_set_skip_dump: Set skip_dump flag, dump will ignore this memory ++ * region ++ * ++ * @mr: the memory region being queried ++ */ ++void memory_region_set_skip_dump(MemoryRegion *mr); ++ ++/** + * memory_region_is_romd: check whether a memory region is in ROMD mode + * + * Returns %true if a memory region is a ROM device and currently set to allow +diff --git a/memory.c b/memory.c +index a71d096..7bd6e87 100644 +--- a/memory.c ++++ b/memory.c +@@ -957,6 +957,11 @@ void memory_region_init_ram_ptr(MemoryRegion *mr, + mr->ram_addr = qemu_ram_alloc_from_ptr(size, ptr, mr); + } + ++void memory_region_set_skip_dump(MemoryRegion *mr) ++{ ++ mr->skip_dump = true; ++} ++ + void memory_region_init_alias(MemoryRegion *mr, + const char *name, + MemoryRegion *orig, +@@ -1047,6 +1052,11 @@ bool memory_region_is_ram(MemoryRegion *mr) + return mr->ram; + } + ++bool memory_region_is_skip_dump(MemoryRegion *mr) ++{ ++ return mr->skip_dump; ++} ++ + bool memory_region_is_logging(MemoryRegion *mr) + { + return mr->dirty_log_mask; +diff --git a/memory_mapping.c b/memory_mapping.c +index 65082d8..a4d59b7 100644 +--- a/memory_mapping.c ++++ b/memory_mapping.c +@@ -203,7 +203,8 @@ static void guest_phys_blocks_region_add(MemoryListener *listener, + GuestPhysBlock *predecessor; + + /* we only care about RAM */ +- if (!memory_region_is_ram(section->mr)) { ++ if (!memory_region_is_ram(section->mr) || ++ memory_region_is_skip_dump(section->mr)) { + return; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-BlockLimits-introduce-max_transfer_length.patch b/SOURCES/kvm-BlockLimits-introduce-max_transfer_length.patch new file mode 100644 index 0000000..c440c6d --- /dev/null +++ b/SOURCES/kvm-BlockLimits-introduce-max_transfer_length.patch @@ -0,0 +1,66 @@ +From fea907b6897cb3e644dcee3c537ce6e64d7850ed Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 11 Jul 2016 05:33:35 +0200 +Subject: [PATCH 2/7] BlockLimits: introduce max_transfer_length + +RH-Author: Fam Zheng +Message-id: <1468215219-30793-3-git-send-email-famz@redhat.com> +Patchwork-id: 71106 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 2/6] BlockLimits: introduce max_transfer_length +Bugzilla: 1318199 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Peter Lieven + +Signed-off-by: Peter Lieven +Reviewed-by: Max Reitz +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 2647fab57d5d5e38b36f8dbda367d688045e6a2d) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block.c | 4 ++++ + include/block/block_int.h | 3 +++ + 2 files changed, 7 insertions(+) + +diff --git a/block.c b/block.c +index ecb2b09..ae756aa 100644 +--- a/block.c ++++ b/block.c +@@ -481,6 +481,7 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) + return; + } + bs->bl.opt_transfer_length = bs->file->bl.opt_transfer_length; ++ bs->bl.max_transfer_length = bs->file->bl.max_transfer_length; + bs->bl.opt_mem_alignment = bs->file->bl.opt_mem_alignment; + } else { + bs->bl.opt_mem_alignment = 512; +@@ -495,6 +496,9 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) + bs->bl.opt_transfer_length = + MAX(bs->bl.opt_transfer_length, + bs->backing_hd->bl.opt_transfer_length); ++ bs->bl.max_transfer_length = ++ MIN_NON_ZERO(bs->bl.max_transfer_length, ++ bs->backing_hd->bl.max_transfer_length); + bs->bl.opt_mem_alignment = + MAX(bs->bl.opt_mem_alignment, + bs->backing_hd->bl.opt_mem_alignment); +diff --git a/include/block/block_int.h b/include/block/block_int.h +index 3f86649..28c34d8 100644 +--- a/include/block/block_int.h ++++ b/include/block/block_int.h +@@ -240,6 +240,9 @@ typedef struct BlockLimits { + /* optimal transfer length in sectors */ + int opt_transfer_length; + ++ /* maximal transfer length in sectors */ ++ int max_transfer_length; ++ + /* memory alignment so that no bounce buffer is needed */ + size_t opt_mem_alignment; + } BlockLimits; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Fix-backport-of-target-i386-add-feature-flags-for-CP.patch b/SOURCES/kvm-Fix-backport-of-target-i386-add-feature-flags-for-CP.patch new file mode 100644 index 0000000..0339170 --- /dev/null +++ b/SOURCES/kvm-Fix-backport-of-target-i386-add-feature-flags-for-CP.patch @@ -0,0 +1,84 @@ +From 7530a2f3975b76711467226f8b279baf36d92e46 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Tue, 6 Sep 2016 21:45:05 +0200 +Subject: [PATCH 1/2] Fix backport of "target-i386: add feature flags for + CPUID[EAX=0xd, ECX=1]" + +RH-Author: Eduardo Habkost +Message-id: <1473198305-8442-1-git-send-email-ehabkost@redhat.com> +Patchwork-id: 72260 +O-Subject: [RHEL-7.3 qemu-kvm PATCH] Fix backport of "target-i386: add feature flags for CPUID[EAX=0xd, ECX=1]" +Bugzilla: 1371619 +RH-Acked-by: Bandan Das +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Miroslav Rezanina + +Upstream status: commit 0bb0b2d2fe7f645ddaf1f0ff40ac669c9feb4aa1 + +commit 5fcaf5176d7545518c76f3aa8ea7ce6fb063c62d (the backport of +upstream commit 0bb0b2d2fe7f645ddaf1f0ff40ac669c9feb4aa1) had a +serious bug: as the qemu-kvm-1.5.3 code doesn't have +FeatureWordInfo and loops for assigning cpu->features, +cpu->features[FEAT_XSAVE] was always zero, so that commit +basically cleared all XSAVE feature bits in all CPU models. + +Fix it by handling FEAT_XSAVE everywhere it matters: in the +plus_features/minus_features handling, in the loading of CPU +model definition, and kvm_cpu_fill_host(). + +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target-i386/cpu.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index 80106ba..1001c47 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -1201,6 +1201,8 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) + } else { + x86_cpu_def->features[FEAT_7_0_EBX] = 0; + } ++ x86_cpu_def->features[FEAT_XSAVE] = ++ kvm_arch_get_supported_cpuid(s, 0xd, 1, R_EAX); + + x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); + x86_cpu_def->features[FEAT_8000_0001_EDX] = +@@ -1281,6 +1283,9 @@ static int kvm_check_features_against_host(X86CPU *cpu) + {&env->features[FEAT_7_0_EBX], + &host_def.features[FEAT_7_0_EBX], + FEAT_7_0_EBX }, ++ {&env->features[FEAT_XSAVE], ++ &host_def.features[FEAT_XSAVE], ++ FEAT_XSAVE }, + {&env->features[FEAT_SVM], + &host_def.features[FEAT_SVM], + FEAT_SVM }, +@@ -1819,6 +1824,7 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) + env->features[FEAT_KVM] |= plus_features[FEAT_KVM]; + env->features[FEAT_SVM] |= plus_features[FEAT_SVM]; + env->features[FEAT_7_0_EBX] |= plus_features[FEAT_7_0_EBX]; ++ env->features[FEAT_XSAVE] |= plus_features[FEAT_XSAVE]; + env->features[FEAT_1_EDX] &= ~minus_features[FEAT_1_EDX]; + env->features[FEAT_1_ECX] &= ~minus_features[FEAT_1_ECX]; + env->features[FEAT_8000_0001_EDX] &= ~minus_features[FEAT_8000_0001_EDX]; +@@ -1827,6 +1833,7 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) + env->features[FEAT_KVM] &= ~minus_features[FEAT_KVM]; + env->features[FEAT_SVM] &= ~minus_features[FEAT_SVM]; + env->features[FEAT_7_0_EBX] &= ~minus_features[FEAT_7_0_EBX]; ++ env->features[FEAT_XSAVE] &= ~minus_features[FEAT_XSAVE]; + + out: + return; +@@ -1962,6 +1969,7 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp) + env->features[FEAT_SVM] = def->features[FEAT_SVM]; + env->features[FEAT_C000_0001_EDX] = def->features[FEAT_C000_0001_EDX]; + env->features[FEAT_7_0_EBX] = def->features[FEAT_7_0_EBX]; ++ env->features[FEAT_XSAVE] = def->features[FEAT_XSAVE]; + env->cpuid_xlevel2 = def->xlevel2; + + object_property_set_str(OBJECT(cpu), def->model_id, "model-id", errp); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-Make-qemu-io-commands-available-in-HMP.patch b/SOURCES/kvm-Make-qemu-io-commands-available-in-HMP.patch new file mode 100644 index 0000000..909d57b --- /dev/null +++ b/SOURCES/kvm-Make-qemu-io-commands-available-in-HMP.patch @@ -0,0 +1,132 @@ +From 6b7e23d3e8ff46e638c9dcd769681b2e1b9da08e Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:35 +0100 +Subject: [PATCH 16/27] Make qemu-io commands available in HMP + +RH-Author: John Snow +Message-id: <1448300320-7772-17-git-send-email-jsnow@redhat.com> +Patchwork-id: 68443 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 16/21] Make qemu-io commands available in HMP +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +It was decided to not make this command available in QMP in order to +make clear that this is not supposed to be a stable API and should be +used only for testing and debugging purposes. + +Signed-off-by: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 587da2c39c9ace168f4d01fa446a54ae998a2553) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + Makefile | 2 +- + Makefile.objs | 1 + + hmp-commands.hx | 16 ++++++++++++++++ + hmp.c | 18 ++++++++++++++++++ + hmp.h | 1 + + 5 files changed, 37 insertions(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index f403057..76eb694 100644 +--- a/Makefile ++++ b/Makefile +@@ -205,7 +205,7 @@ qemu-img.o: qemu-img-cmds.h + + qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a + qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a +-qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o $(block-obj-y) libqemuutil.a libqemustub.a ++qemu-io$(EXESUF): qemu-io.o $(block-obj-y) libqemuutil.a libqemustub.a + + qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o + +diff --git a/Makefile.objs b/Makefile.objs +index f83a5b2..74f722e 100644 +--- a/Makefile.objs ++++ b/Makefile.objs +@@ -13,6 +13,7 @@ block-obj-$(CONFIG_POSIX) += aio-posix.o + block-obj-$(CONFIG_WIN32) += aio-win32.o + block-obj-y += block/ + block-obj-y += qapi-types.o qapi-visit.o ++block-obj-y += qemu-io-cmds.o + + block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o + block-obj-y += qemu-coroutine-sleep.o +diff --git a/hmp-commands.hx b/hmp-commands.hx +index 58498f7..7e1855a 100644 +--- a/hmp-commands.hx ++++ b/hmp-commands.hx +@@ -1592,6 +1592,22 @@ Removes the chardev @var{id}. + ETEXI + + { ++ .name = "qemu-io", ++ .args_type = "device:B,command:s", ++ .params = "[device] \"[command]\"", ++ .help = "run a qemu-io command on a block device", ++ .mhandler.cmd = hmp_qemu_io, ++ }, ++ ++STEXI ++@item qemu-io @var{device} @var{command} ++@findex qemu-io ++ ++Executes a qemu-io command on the given block device. ++ ++ETEXI ++ ++ { + .name = "info", + .args_type = "item:s?", + .params = "[subcommand]", +diff --git a/hmp.c b/hmp.c +index 1805926..e1d92f4 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -22,6 +22,7 @@ + #include "qemu/sockets.h" + #include "monitor/monitor.h" + #include "ui/console.h" ++#include "qemu-io.h" + + static void hmp_handle_error(Monitor *mon, Error **errp) + { +@@ -1448,3 +1449,20 @@ void hmp_chardev_remove(Monitor *mon, const QDict *qdict) + qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err); + hmp_handle_error(mon, &local_err); + } ++ ++void hmp_qemu_io(Monitor *mon, const QDict *qdict) ++{ ++ BlockDriverState *bs; ++ const char* device = qdict_get_str(qdict, "device"); ++ const char* command = qdict_get_str(qdict, "command"); ++ Error *err = NULL; ++ ++ bs = bdrv_find(device); ++ if (bs) { ++ qemuio_command(bs, command); ++ } else { ++ error_set(&err, QERR_DEVICE_NOT_FOUND, device); ++ } ++ ++ hmp_handle_error(mon, &err); ++} +diff --git a/hmp.h b/hmp.h +index 9b2c9ce..b27ef3d 100644 +--- a/hmp.h ++++ b/hmp.h +@@ -86,5 +86,6 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict); + void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict); + void hmp_chardev_add(Monitor *mon, const QDict *qdict); + void hmp_chardev_remove(Monitor *mon, const QDict *qdict); ++void hmp_qemu_io(Monitor *mon, const QDict *qdict); + + #endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-acpi-add-function-to-extract-oem_id-and-oem_table_id.patch b/SOURCES/kvm-acpi-add-function-to-extract-oem_id-and-oem_table_id.patch new file mode 100644 index 0000000..4660d3b --- /dev/null +++ b/SOURCES/kvm-acpi-add-function-to-extract-oem_id-and-oem_table_id.patch @@ -0,0 +1,89 @@ +From 5ccdcc1c49246cce9b1536e28a4977c65d72531c Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Wed, 11 May 2016 12:33:47 +0200 +Subject: [PATCH 08/10] acpi: add function to extract oem_id and oem_table_id + from the user's SLIC + +RH-Author: Laszlo Ersek +Message-id: <1462970028-10959-7-git-send-email-lersek@redhat.com> +Patchwork-id: 70383 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 6/7] acpi: add function to extract oem_id and oem_table_id from the user's SLIC +Bugzilla: 1330969 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Thomas Huth + +The acpi_get_slic_oem() function stores pointers to these fields in the +(first) SLIC table that the user passes in with the -acpitable switch. + +Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) +Cc: Igor Mammedov (supporter:ACPI/SMBIOS) +Cc: Richard W.M. Jones +Cc: Aleksei Kovura +Cc: Michael Tokarev +Cc: Steven Newbury +RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 +LP: https://bugs.launchpad.net/qemu/+bug/1533848 +Signed-off-by: Laszlo Ersek +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Steven Newbury +(cherry picked from commit 88594e4fd1e916b778968b2bdd8d7375ca2fe8d8) +Signed-off-by: Laszlo Ersek +--- + include/hw/acpi/acpi.h | 7 +++++++ + hw/acpi/core.c | 16 ++++++++++++++++ + 2 files changed, 23 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + hw/acpi/core.c | 16 ++++++++++++++++ + include/hw/acpi/acpi.h | 7 +++++++ + 2 files changed, 23 insertions(+) + +diff --git a/hw/acpi/core.c b/hw/acpi/core.c +index 88efba7..99c5918 100644 +--- a/hw/acpi/core.c ++++ b/hw/acpi/core.c +@@ -349,6 +349,22 @@ uint8_t *acpi_table_next(uint8_t *current) + } + } + ++int acpi_get_slic_oem(AcpiSlicOem *oem) ++{ ++ uint8_t *u; ++ ++ for (u = acpi_table_first(); u; u = acpi_table_next(u)) { ++ struct acpi_table_header *hdr = (void *)(u - sizeof(hdr->_length)); ++ ++ if (memcmp(hdr->sig, "SLIC", 4) == 0) { ++ oem->id = hdr->oem_id; ++ oem->table_id = hdr->oem_table_id; ++ return 0; ++ } ++ } ++ return -1; ++} ++ + static void acpi_notify_wakeup(Notifier *notifier, void *data) + { + ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup); +diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h +index bb7136d..1e59ec9 100644 +--- a/include/hw/acpi/acpi.h ++++ b/include/hw/acpi/acpi.h +@@ -171,4 +171,11 @@ unsigned acpi_table_len(void *current); + void acpi_table_add(const QemuOpts *opts, Error **errp); + void acpi_table_add_builtin(const QemuOpts *opts, Error **errp); + ++typedef struct AcpiSlicOem AcpiSlicOem; ++struct AcpiSlicOem { ++ char *id; ++ char *table_id; ++}; ++int acpi_get_slic_oem(AcpiSlicOem *oem); ++ + #endif /* !QEMU_HW_ACPI_H */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-acpi-expose-oem_id-and-oem_table_id-in-build_rsdt.patch b/SOURCES/kvm-acpi-expose-oem_id-and-oem_table_id-in-build_rsdt.patch new file mode 100644 index 0000000..1e8bf05 --- /dev/null +++ b/SOURCES/kvm-acpi-expose-oem_id-and-oem_table_id-in-build_rsdt.patch @@ -0,0 +1,92 @@ +From 39f2d80c57f648afd2eab27816e8f93cf48e718d Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Wed, 11 May 2016 12:33:46 +0200 +Subject: [PATCH 07/10] acpi: expose oem_id and oem_table_id in build_rsdt() + +RH-Author: Laszlo Ersek +Message-id: <1462970028-10959-6-git-send-email-lersek@redhat.com> +Patchwork-id: 70382 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 5/7] acpi: expose oem_id and oem_table_id in build_rsdt() +Bugzilla: 1330969 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Thomas Huth + +Since build_rsdt() is implemented as common utility code (in +"hw/acpi/aml-build.c"), it should expose -- and forward -- the oem_id and +oem_table_id parameters between board code and the generic build_header() +function. + +Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) +Cc: Igor Mammedov (supporter:ACPI/SMBIOS) +Cc: Shannon Zhao (maintainer:ARM ACPI Subsystem) +Cc: Paolo Bonzini (maintainer:X86) +Cc: Richard W.M. Jones +Cc: Aleksei Kovura +Cc: Michael Tokarev +Cc: Steven Newbury +RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 +LP: https://bugs.launchpad.net/qemu/+bug/1533848 +Signed-off-by: Laszlo Ersek +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Shannon Zhao +(cherry picked from commit 5151355898699eb66fad0a710b8b6011690a0dfc) +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/acpi/aml-build.c + hw/arm/virt-acpi-build.c + hw/i386/acpi-build.c + include/hw/acpi/aml-build.h + +RHEL-7 backport note: this is actually a manual reimplementation of the +upstream patch, which is mostly mechanic. A clean cherry-pick would depend +on a lot of reorganizatorial upstream patches (e.g., 658c27181bf3 +("hw/i386/acpi-build: move generic acpi building helpers into dedictated +file")), and many new features that overlap with ACPI generation (e.g., +the "virt" machtype of the arm/aarch64 targets). + +Signed-off-by: Laszlo Ersek +--- + hw/i386/acpi-build.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) +--- + hw/i386/acpi-build.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 4839b0e..d9433e6 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -951,7 +951,8 @@ build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc) + + /* Build final rsdt table */ + static void +-build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets) ++build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets, ++ const char *oem_id, const char *oem_table_id) + { + AcpiRsdtDescriptorRev1 *rsdt; + size_t rsdt_len; +@@ -970,7 +971,7 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets) + sizeof(uint32_t)); + } + build_header(linker, table_data, +- (void *)rsdt, "RSDT", rsdt_len, 1, NULL, NULL); ++ (void *)rsdt, "RSDT", rsdt_len, 1, oem_id, oem_table_id); + } + + static GArray * +@@ -1126,7 +1127,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) + + /* RSDT is pointed to by RSDP */ + rsdt = tables->table_data->len; +- build_rsdt(tables->table_data, tables->linker, table_offsets); ++ build_rsdt(tables->table_data, tables->linker, table_offsets, NULL, NULL); + + /* RSDP is in FSEG memory, so allocate it separately */ + build_rsdp(tables->rsdp, tables->linker, rsdt); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-acpi-fix-endian-ness-for-table-ids.patch b/SOURCES/kvm-acpi-fix-endian-ness-for-table-ids.patch new file mode 100644 index 0000000..5c998a6 --- /dev/null +++ b/SOURCES/kvm-acpi-fix-endian-ness-for-table-ids.patch @@ -0,0 +1,249 @@ +From 87f01cd69488bf39e80c422b92717029fed0bef6 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Wed, 11 May 2016 12:33:43 +0200 +Subject: [PATCH 04/10] acpi: fix endian-ness for table ids + +RH-Author: Laszlo Ersek +Message-id: <1462970028-10959-3-git-send-email-lersek@redhat.com> +Patchwork-id: 70379 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 2/7] acpi: fix endian-ness for table ids +Bugzilla: 1330969 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Thomas Huth + +From: "Michael S. Tsirkin" + +when using signature for table ID, we forgot to byte-swap it. +signatures are really ASCII strings, let's treat them as such. +While at it, get rid of most of _SIGNATURE macros. + +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 821e3227863ea8db057190e578efa0f1f57ed9de) + +RHEL-7 backport notes: this patch is being backported only to decrease the +number of conflicts in the upcoming patches; we only support x86_64 hosts, +which is unaffected by the endianness issue described in the upstream +commit message. + +Signed-off-by: Laszlo Ersek +--- + hw/i386/acpi-defs.h | 14 -------------- + hw/i386/acpi-build.c | 31 ++++++++++++++++--------------- + 2 files changed, 16 insertions(+), 29 deletions(-) + +Signed-off-by: Miroslav Rezanina +--- + hw/i386/acpi-build.c | 31 ++++++++++++++++--------------- + hw/i386/acpi-defs.h | 14 -------------- + 2 files changed, 16 insertions(+), 29 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index a3a4c3b..be32bc3 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -243,14 +243,14 @@ static void acpi_get_pci_info(PcPciInfo *info) + + static void + build_header(GArray *linker, GArray *table_data, +- AcpiTableHeader *h, uint32_t sig, int len, uint8_t rev) ++ AcpiTableHeader *h, const char *sig, int len, uint8_t rev) + { +- h->signature = cpu_to_le32(sig); ++ memcpy(&h->signature, sig, 4); + h->length = cpu_to_le32(len); + h->revision = rev; + memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); + memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4); +- memcpy(h->oem_table_id + 4, (void *)&sig, 4); ++ memcpy(h->oem_table_id + 4, sig, 4); + h->oem_revision = cpu_to_le32(1); + memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4); + h->asl_compiler_revision = cpu_to_le32(1); +@@ -463,7 +463,7 @@ static void + build_facs(GArray *table_data, GArray *linker, PcGuestInfo *guest_info) + { + AcpiFacsDescriptorRev1 *facs = acpi_data_push(table_data, sizeof *facs); +- facs->signature = cpu_to_le32(ACPI_FACS_SIGNATURE); ++ memcpy(&facs->signature, "FACS", 4); + facs->length = cpu_to_le32(sizeof(*facs)); + } + +@@ -520,7 +520,7 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, + fadt_setup(fadt, pm); + + build_header(linker, table_data, +- (void *)fadt, ACPI_FACP_SIGNATURE, sizeof(*fadt), 1); ++ (void *)fadt, "FACP", sizeof(*fadt), 1); + } + + static void +@@ -589,7 +589,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu, + local_nmi->lint = 1; /* ACPI_LINT1 */ + + build_header(linker, table_data, +- (void *)(table_data->data + madt_start), ACPI_APIC_SIGNATURE, ++ (void *)(table_data->data + madt_start), "APIC", + table_data->len - madt_start, 1); + } + +@@ -782,7 +782,7 @@ build_ssdt(GArray *table_data, GArray *linker, + + build_header(linker, table_data, + (void *)(table_data->data + ssdt_start), +- ACPI_SSDT_SIGNATURE, table_data->len - ssdt_start, 1); ++ "SSDT", table_data->len - ssdt_start, 1); + } + + static void +@@ -797,7 +797,7 @@ build_hpet(GArray *table_data, GArray *linker) + hpet->timer_block_id = cpu_to_le32(0x8086a201); + hpet->addr.address = cpu_to_le64(HPET_BASE); + build_header(linker, table_data, +- (void *)hpet, ACPI_HPET_SIGNATURE, sizeof(*hpet), 1); ++ (void *)hpet, "HPET", sizeof(*hpet), 1); + } + + static void +@@ -889,7 +889,7 @@ build_srat(GArray *table_data, GArray *linker, + + build_header(linker, table_data, + (void *)(table_data->data + srat_start), +- ACPI_SRAT_SIGNATURE, ++ "SRAT", + table_data->len - srat_start, 1); + } + +@@ -897,7 +897,7 @@ static void + build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info) + { + AcpiTableMcfg *mcfg; +- uint32_t sig; ++ const char *sig; + int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]); + + mcfg = acpi_data_push(table_data, len); +@@ -914,9 +914,10 @@ build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info) + * ACPI spec requires OSPMs to ignore such tables. + */ + if (info->mcfg_base == PCIE_BASE_ADDR_UNMAPPED) { +- sig = ACPI_RSRV_SIGNATURE; ++ /* Reserved signature: ignored by OSPM */ ++ sig = "QEMU"; + } else { +- sig = ACPI_MCFG_SIGNATURE; ++ sig = "MCFG"; + } + build_header(linker, table_data, (void *)mcfg, sig, len, 1); + } +@@ -932,7 +933,7 @@ build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc) + memcpy(dsdt, misc->dsdt_code, misc->dsdt_size); + + memset(dsdt, 0, sizeof *dsdt); +- build_header(linker, table_data, dsdt, ACPI_DSDT_SIGNATURE, ++ build_header(linker, table_data, dsdt, "DSDT", + misc->dsdt_size, 1); + } + +@@ -957,7 +958,7 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets) + sizeof(uint32_t)); + } + build_header(linker, table_data, +- (void *)rsdt, ACPI_RSDT_SIGNATURE, rsdt_len, 1); ++ (void *)rsdt, "RSDT", rsdt_len, 1); + } + + static GArray * +@@ -968,7 +969,7 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) + bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 1, + true /* fseg memory */); + +- rsdp->signature = cpu_to_le64(ACPI_RSDP_SIGNATURE); ++ memcpy(&rsdp->signature, "RSD PTR ", 8); + memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, 6); + rsdp->rsdt_physical_address = cpu_to_le32(rsdt); + /* Address to be filled by Guest linker */ +diff --git a/hw/i386/acpi-defs.h b/hw/i386/acpi-defs.h +index 78ca204..e93babb 100644 +--- a/hw/i386/acpi-defs.h ++++ b/hw/i386/acpi-defs.h +@@ -52,8 +52,6 @@ struct Acpi20GenericAddress { + } QEMU_PACKED; + typedef struct Acpi20GenericAddress Acpi20GenericAddress; + +-#define ACPI_RSDP_SIGNATURE 0x2052545020445352LL // "RSD PTR " +- + struct AcpiRsdpDescriptor { /* Root System Descriptor Pointer */ + uint64_t signature; /* ACPI signature, contains "RSD PTR " */ + uint8_t checksum; /* To make sum of struct == 0 */ +@@ -92,7 +90,6 @@ typedef struct AcpiTableHeader AcpiTableHeader; + /* + * ACPI 1.0 Fixed ACPI Description Table (FADT) + */ +-#define ACPI_FACP_SIGNATURE 0x50434146 // FACP + struct AcpiFadtDescriptorRev1 + { + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ +@@ -141,7 +138,6 @@ typedef struct AcpiFadtDescriptorRev1 AcpiFadtDescriptorRev1; + /* + * ACPI 1.0 Root System Description Table (RSDT) + */ +-#define ACPI_RSDT_SIGNATURE 0x54445352 // RSDT + struct AcpiRsdtDescriptorRev1 + { + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ +@@ -153,7 +149,6 @@ typedef struct AcpiRsdtDescriptorRev1 AcpiRsdtDescriptorRev1; + /* + * ACPI 1.0 Firmware ACPI Control Structure (FACS) + */ +-#define ACPI_FACS_SIGNATURE 0x53434146 // FACS + struct AcpiFacsDescriptorRev1 + { + uint32_t signature; /* ACPI Signature */ +@@ -169,7 +164,6 @@ typedef struct AcpiFacsDescriptorRev1 AcpiFacsDescriptorRev1; + /* + * Differentiated System Description Table (DSDT) + */ +-#define ACPI_DSDT_SIGNATURE 0x54445344 // DSDT + + /* + * MADT values and structures +@@ -182,7 +176,6 @@ typedef struct AcpiFacsDescriptorRev1 AcpiFacsDescriptorRev1; + + /* Master MADT */ + +-#define ACPI_APIC_SIGNATURE 0x43495041 // APIC + struct AcpiMultipleApicTable + { + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ +@@ -253,7 +246,6 @@ typedef struct AcpiMadtLocalNmi AcpiMadtLocalNmi; + /* + * HPET Description Table + */ +-#define ACPI_HPET_SIGNATURE 0x54455048 // HPET + struct Acpi20Hpet { + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + uint32_t timer_block_id; +@@ -268,7 +260,6 @@ typedef struct Acpi20Hpet Acpi20Hpet; + * SRAT (NUMA topology description) table + */ + +-#define ACPI_SRAT_SIGNATURE 0x54415253 // SRAT + struct AcpiSystemResourceAffinityTable + { + ACPI_TABLE_HEADER_DEF +@@ -316,11 +307,6 @@ struct AcpiMcfgAllocation { + } QEMU_PACKED; + typedef struct AcpiMcfgAllocation AcpiMcfgAllocation; + +-#define ACPI_MCFG_SIGNATURE 0x4746434d // MCFG +- +-/* Reserved signature: ignored by OSPM */ +-#define ACPI_RSRV_SIGNATURE 0x554d4551 // QEMU +- + struct AcpiTableMcfg { + ACPI_TABLE_HEADER_DEF; + uint8_t reserved[8]; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-acpi-strip-compiler-info-in-built-in-DSDT.patch b/SOURCES/kvm-acpi-strip-compiler-info-in-built-in-DSDT.patch new file mode 100644 index 0000000..816c197 --- /dev/null +++ b/SOURCES/kvm-acpi-strip-compiler-info-in-built-in-DSDT.patch @@ -0,0 +1,61 @@ +From 464ceecd1e9c070e613624fb896df54b7e4a3e38 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Wed, 11 May 2016 12:33:42 +0200 +Subject: [PATCH 03/10] acpi: strip compiler info in built-in DSDT + +RH-Author: Laszlo Ersek +Message-id: <1462970028-10959-2-git-send-email-lersek@redhat.com> +Patchwork-id: 70378 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 1/7] acpi: strip compiler info in built-in DSDT +Bugzilla: 1330969 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Thomas Huth + +From: "Michael S. Tsirkin" + +IASL stores it's revision in each table header it generates. +That's not nice since guests will see a change each time they move +between hypervisors. We generally fill our own info for tables, but we +(and seabios) forgot to do this for the built-in DSDT. + +Modifications in DSDT table: + OEM ID: "BXPC" -> "BOCHS " + OEM Table ID: "BXDSDT" -> "BXPCDSDT" + Compiler ID: "INTL" -> "BXPC" + Compiler Version: 0x20130823 -> 0x00000001 + +Tested-by: Marcel Apfelbaum +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 53db092ad1c81c30a617f44e83e8fb9e27c001ba) +Signed-off-by: Laszlo Ersek +Signed-off-by: Miroslav Rezanina +--- + hw/i386/acpi-build.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 8be1286..a3a4c3b 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -924,10 +924,16 @@ build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info) + static void + build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc) + { +- void *dsdt; ++ AcpiTableHeader *dsdt; ++ + assert(misc->dsdt_code && misc->dsdt_size); ++ + dsdt = acpi_data_push(table_data, misc->dsdt_size); + memcpy(dsdt, misc->dsdt_code, misc->dsdt_size); ++ ++ memset(dsdt, 0, sizeof *dsdt); ++ build_header(linker, table_data, dsdt, ACPI_DSDT_SIGNATURE, ++ misc->dsdt_size, 1); + } + + /* Build final rsdt table */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-acpi-support-specified-oem-table-id-for-build_header.patch b/SOURCES/kvm-acpi-support-specified-oem-table-id-for-build_header.patch new file mode 100644 index 0000000..8fd5426 --- /dev/null +++ b/SOURCES/kvm-acpi-support-specified-oem-table-id-for-build_header.patch @@ -0,0 +1,154 @@ +From b36e60614f9c4a6eb3f417422c3cb99402b82963 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Wed, 11 May 2016 12:33:44 +0200 +Subject: [PATCH 05/10] acpi: support specified oem table id for build_header + +RH-Author: Laszlo Ersek +Message-id: <1462970028-10959-4-git-send-email-lersek@redhat.com> +Patchwork-id: 70380 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 3/7] acpi: support specified oem table id for build_header +Bugzilla: 1330969 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Thomas Huth + +From: Xiao Guangrong + +Let build_header() support specified OEM table id so that we can build +multiple SSDT later + +If the oem table id is not specified (aka, NULL), we use the default id +instead as the previous behavior + +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Xiao Guangrong +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 8870ca0e94f2524644812dd759863c0851ffb870) +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/acpi/aml-build.c + hw/arm/virt-acpi-build.c + hw/i386/acpi-build.c + include/hw/acpi/aml-build.h + +RHEL-7 backport note: this is actually a manual reimplementation of the +upstream patch, which is mostly mechanic. A clean cherry-pick would depend +on a lot of reorganizatorial upstream patches (e.g., 658c27181bf3 +("hw/i386/acpi-build: move generic acpi building helpers into dedictated +file")), and many new features that overlap with ACPI generation (e.g., +the "virt" machtype of the arm/aarch64 targets). + +Signed-off-by: Laszlo Ersek +--- + hw/i386/acpi-build.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) +--- + hw/i386/acpi-build.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index be32bc3..a9d9f97 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -243,14 +243,21 @@ static void acpi_get_pci_info(PcPciInfo *info) + + static void + build_header(GArray *linker, GArray *table_data, +- AcpiTableHeader *h, const char *sig, int len, uint8_t rev) ++ AcpiTableHeader *h, const char *sig, int len, uint8_t rev, ++ const char *oem_table_id) + { + memcpy(&h->signature, sig, 4); + h->length = cpu_to_le32(len); + h->revision = rev; + memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); +- memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4); +- memcpy(h->oem_table_id + 4, sig, 4); ++ ++ if (oem_table_id) { ++ strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id)); ++ } else { ++ memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4); ++ memcpy(h->oem_table_id + 4, sig, 4); ++ } ++ + h->oem_revision = cpu_to_le32(1); + memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4); + h->asl_compiler_revision = cpu_to_le32(1); +@@ -520,7 +527,7 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, + fadt_setup(fadt, pm); + + build_header(linker, table_data, +- (void *)fadt, "FACP", sizeof(*fadt), 1); ++ (void *)fadt, "FACP", sizeof(*fadt), 1, NULL); + } + + static void +@@ -590,7 +597,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu, + + build_header(linker, table_data, + (void *)(table_data->data + madt_start), "APIC", +- table_data->len - madt_start, 1); ++ table_data->len - madt_start, 1, NULL); + } + + /* Encode a hex value */ +@@ -782,7 +789,7 @@ build_ssdt(GArray *table_data, GArray *linker, + + build_header(linker, table_data, + (void *)(table_data->data + ssdt_start), +- "SSDT", table_data->len - ssdt_start, 1); ++ "SSDT", table_data->len - ssdt_start, 1, NULL); + } + + static void +@@ -797,7 +804,7 @@ build_hpet(GArray *table_data, GArray *linker) + hpet->timer_block_id = cpu_to_le32(0x8086a201); + hpet->addr.address = cpu_to_le64(HPET_BASE); + build_header(linker, table_data, +- (void *)hpet, "HPET", sizeof(*hpet), 1); ++ (void *)hpet, "HPET", sizeof(*hpet), 1, NULL); + } + + static void +@@ -890,7 +897,7 @@ build_srat(GArray *table_data, GArray *linker, + build_header(linker, table_data, + (void *)(table_data->data + srat_start), + "SRAT", +- table_data->len - srat_start, 1); ++ table_data->len - srat_start, 1, NULL); + } + + static void +@@ -919,7 +926,7 @@ build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info) + } else { + sig = "MCFG"; + } +- build_header(linker, table_data, (void *)mcfg, sig, len, 1); ++ build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL); + } + + static void +@@ -934,7 +941,7 @@ build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc) + + memset(dsdt, 0, sizeof *dsdt); + build_header(linker, table_data, dsdt, "DSDT", +- misc->dsdt_size, 1); ++ misc->dsdt_size, 1, NULL); + } + + /* Build final rsdt table */ +@@ -958,7 +965,7 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets) + sizeof(uint32_t)); + } + build_header(linker, table_data, +- (void *)rsdt, "RSDT", rsdt_len, 1); ++ (void *)rsdt, "RSDT", rsdt_len, 1, NULL); + } + + static GArray * +-- +1.8.3.1 + diff --git a/SOURCES/kvm-acpi-take-oem_id-in-build_header-optionally.patch b/SOURCES/kvm-acpi-take-oem_id-in-build_header-optionally.patch new file mode 100644 index 0000000..8670c32 --- /dev/null +++ b/SOURCES/kvm-acpi-take-oem_id-in-build_header-optionally.patch @@ -0,0 +1,157 @@ +From 0decede8a51451da8f5913b0ad13c8e3bdcef582 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Wed, 11 May 2016 12:33:45 +0200 +Subject: [PATCH 06/10] acpi: take oem_id in build_header(), optionally + +RH-Author: Laszlo Ersek +Message-id: <1462970028-10959-5-git-send-email-lersek@redhat.com> +Patchwork-id: 70381 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 4/7] acpi: take oem_id in build_header(), optionally +Bugzilla: 1330969 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Thomas Huth + +This patch is the continuation of commit 8870ca0e94f2 ("acpi: support +specified oem table id for build_header"). It will allow us to control the +OEM ID field too in the SDT header. + +Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) +Cc: Igor Mammedov (supporter:ACPI/SMBIOS) +Cc: Xiao Guangrong (maintainer:NVDIMM) +Cc: Shannon Zhao (maintainer:ARM ACPI Subsystem) +Cc: Paolo Bonzini (maintainer:X86) +Cc: Richard W.M. Jones +Cc: Aleksei Kovura +Cc: Michael Tokarev +Cc: Steven Newbury +RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 +LP: https://bugs.launchpad.net/qemu/+bug/1533848 +Signed-off-by: Laszlo Ersek +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Shannon Zhao +(cherry picked from commit 37ad223c515da2fe9f1c679768cb5ccaa42e57e1) +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/acpi/aml-build.c + hw/acpi/nvdimm.c + hw/arm/virt-acpi-build.c + hw/i386/acpi-build.c + include/hw/acpi/aml-build.h + +RHEL-7 backport note: this is actually a manual reimplementation of the +upstream patch, which is mostly mechanic. A clean cherry-pick would depend +on a lot of reorganizatorial upstream patches (e.g., 658c27181bf3 +("hw/i386/acpi-build: move generic acpi building helpers into dedictated +file")), and many new features that overlap with ACPI generation (e.g., +the "virt" machtype of the arm/aarch64 targets). + +Signed-off-by: Laszlo Ersek +--- + hw/i386/acpi-build.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) +--- + hw/i386/acpi-build.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index a9d9f97..4839b0e 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -244,12 +244,17 @@ static void acpi_get_pci_info(PcPciInfo *info) + static void + build_header(GArray *linker, GArray *table_data, + AcpiTableHeader *h, const char *sig, int len, uint8_t rev, +- const char *oem_table_id) ++ const char *oem_id, const char *oem_table_id) + { + memcpy(&h->signature, sig, 4); + h->length = cpu_to_le32(len); + h->revision = rev; +- memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); ++ ++ if (oem_id) { ++ strncpy((char *)h->oem_id, oem_id, sizeof h->oem_id); ++ } else { ++ memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6); ++ } + + if (oem_table_id) { + strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id)); +@@ -527,7 +532,7 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, + fadt_setup(fadt, pm); + + build_header(linker, table_data, +- (void *)fadt, "FACP", sizeof(*fadt), 1, NULL); ++ (void *)fadt, "FACP", sizeof(*fadt), 1, NULL, NULL); + } + + static void +@@ -597,7 +602,7 @@ build_madt(GArray *table_data, GArray *linker, AcpiCpuInfo *cpu, + + build_header(linker, table_data, + (void *)(table_data->data + madt_start), "APIC", +- table_data->len - madt_start, 1, NULL); ++ table_data->len - madt_start, 1, NULL, NULL); + } + + /* Encode a hex value */ +@@ -789,7 +794,7 @@ build_ssdt(GArray *table_data, GArray *linker, + + build_header(linker, table_data, + (void *)(table_data->data + ssdt_start), +- "SSDT", table_data->len - ssdt_start, 1, NULL); ++ "SSDT", table_data->len - ssdt_start, 1, NULL, NULL); + } + + static void +@@ -804,7 +809,7 @@ build_hpet(GArray *table_data, GArray *linker) + hpet->timer_block_id = cpu_to_le32(0x8086a201); + hpet->addr.address = cpu_to_le64(HPET_BASE); + build_header(linker, table_data, +- (void *)hpet, "HPET", sizeof(*hpet), 1, NULL); ++ (void *)hpet, "HPET", sizeof(*hpet), 1, NULL, NULL); + } + + static void +@@ -897,7 +902,7 @@ build_srat(GArray *table_data, GArray *linker, + build_header(linker, table_data, + (void *)(table_data->data + srat_start), + "SRAT", +- table_data->len - srat_start, 1, NULL); ++ table_data->len - srat_start, 1, NULL, NULL); + } + + static void +@@ -926,7 +931,7 @@ build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info) + } else { + sig = "MCFG"; + } +- build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL); ++ build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL); + } + + static void +@@ -941,7 +946,7 @@ build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc) + + memset(dsdt, 0, sizeof *dsdt); + build_header(linker, table_data, dsdt, "DSDT", +- misc->dsdt_size, 1, NULL); ++ misc->dsdt_size, 1, NULL, NULL); + } + + /* Build final rsdt table */ +@@ -965,7 +970,7 @@ build_rsdt(GArray *table_data, GArray *linker, GArray *table_offsets) + sizeof(uint32_t)); + } + build_header(linker, table_data, +- (void *)rsdt, "RSDT", rsdt_len, 1, NULL); ++ (void *)rsdt, "RSDT", rsdt_len, 1, NULL, NULL); + } + + static GArray * +-- +1.8.3.1 + diff --git a/SOURCES/kvm-blkdebug-Add-BLKDBG_FLUSH_TO_OS-DISK-events.patch b/SOURCES/kvm-blkdebug-Add-BLKDBG_FLUSH_TO_OS-DISK-events.patch new file mode 100644 index 0000000..b65b85e --- /dev/null +++ b/SOURCES/kvm-blkdebug-Add-BLKDBG_FLUSH_TO_OS-DISK-events.patch @@ -0,0 +1,100 @@ +From 89f3f5eafd6aed8a79b4570553af711dffc3a1d6 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:36 +0100 +Subject: [PATCH 17/27] blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events + +RH-Author: John Snow +Message-id: <1448300320-7772-18-git-send-email-jsnow@redhat.com> +Patchwork-id: 68448 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 17/21] blkdebug: Add BLKDBG_FLUSH_TO_OS/DISK events +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Signed-off-by: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit bf736fe34caba0688c9095c31b9d097ea15c1296) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina + +Conflicts: + block/blkdebug.c: debug event ordering + include/block/block.h: debug event ordering + +Signed-off-by: John Snow +--- + block.c | 8 ++++---- + block/blkdebug.c | 3 +++ + include/block/block.h | 3 +++ + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/block.c b/block.c +index bc6e75c..ecb2b09 100644 +--- a/block.c ++++ b/block.c +@@ -4026,13 +4026,11 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf, + + void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event) + { +- BlockDriver *drv = bs->drv; +- +- if (!drv || !drv->bdrv_debug_event) { ++ if (!bs || !bs->drv || !bs->drv->bdrv_debug_event) { + return; + } + +- drv->bdrv_debug_event(bs, event); ++ bs->drv->bdrv_debug_event(bs, event); + } + + int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event, +@@ -4879,6 +4877,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) + } + + /* Write back cached data to the OS even with cache=unsafe */ ++ BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_OS); + if (bs->drv->bdrv_co_flush_to_os) { + ret = bs->drv->bdrv_co_flush_to_os(bs); + if (ret < 0) { +@@ -4891,6 +4890,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) + goto flush_parent; + } + ++ BLKDBG_EVENT(bs->file, BLKDBG_FLUSH_TO_DISK); + if (bs->drv->bdrv_co_flush_to_disk) { + ret = bs->drv->bdrv_co_flush_to_disk(bs); + } else if (bs->drv->bdrv_aio_flush) { +diff --git a/block/blkdebug.c b/block/blkdebug.c +index c61ce52..8e468b2 100644 +--- a/block/blkdebug.c ++++ b/block/blkdebug.c +@@ -184,6 +184,9 @@ static const char *event_names[BLKDBG_EVENT_MAX] = { + [BLKDBG_CLUSTER_ALLOC_BYTES] = "cluster_alloc_bytes", + [BLKDBG_CLUSTER_FREE] = "cluster_free", + ++ [BLKDBG_FLUSH_TO_OS] = "flush_to_os", ++ [BLKDBG_FLUSH_TO_DISK] = "flush_to_disk", ++ + [BLKDBG_PWRITEV_RMW_HEAD] = "pwritev_rmw.head", + [BLKDBG_PWRITEV_RMW_AFTER_HEAD] = "pwritev_rmw.after_head", + [BLKDBG_PWRITEV_RMW_TAIL] = "pwritev_rmw.tail", +diff --git a/include/block/block.h b/include/block/block.h +index 8339cac..75147b2 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -508,6 +508,9 @@ typedef enum { + BLKDBG_CLUSTER_ALLOC_BYTES, + BLKDBG_CLUSTER_FREE, + ++ BLKDBG_FLUSH_TO_OS, ++ BLKDBG_FLUSH_TO_DISK, ++ + BLKDBG_PWRITEV_RMW_HEAD, + BLKDBG_PWRITEV_RMW_AFTER_HEAD, + BLKDBG_PWRITEV_RMW_TAIL, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-backend-expose-bs-bl.max_transfer_length.patch b/SOURCES/kvm-block-backend-expose-bs-bl.max_transfer_length.patch new file mode 100644 index 0000000..587dc00 --- /dev/null +++ b/SOURCES/kvm-block-backend-expose-bs-bl.max_transfer_length.patch @@ -0,0 +1,66 @@ +From b9d7b6bbaa64404eb9b4a65d0af841bfae5c9089 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 11 Jul 2016 05:33:36 +0200 +Subject: [PATCH 3/7] block-backend: expose bs->bl.max_transfer_length + +RH-Author: Fam Zheng +Message-id: <1468215219-30793-4-git-send-email-famz@redhat.com> +Patchwork-id: 71107 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 3/6] block-backend: expose bs->bl.max_transfer_length +Bugzilla: 1318199 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Peter Lieven + +Signed-off-by: Peter Lieven +Reviewed-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 454057b7d9b9ad141bd5df8c4075745e56b4870f) +Signed-off-by: Miroslav Rezanina + +Conflicts: + block/block-backend.c + include/sysemu/block-backend.h + +Downstream doesn't have BlockBackend yet, so "blk_" -> "bdrv_" and put +the function in block.c. + +Signed-off-by: Fam Zheng +--- + block.c | 5 +++++ + include/block/block.h | 1 + + 2 files changed, 6 insertions(+) + +diff --git a/block.c b/block.c +index ae756aa..bdcd741 100644 +--- a/block.c ++++ b/block.c +@@ -3656,6 +3656,11 @@ int bdrv_get_flags(BlockDriverState *bs) + return bs->open_flags; + } + ++int bdrv_get_max_transfer_length(BlockDriverState *bs) ++{ ++ return bs->bl.max_transfer_length; ++} ++ + int bdrv_flush_all(void) + { + BlockDriverState *bs; +diff --git a/include/block/block.h b/include/block/block.h +index 75147b2..d29733a 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -379,6 +379,7 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name), + void *opaque); + const char *bdrv_get_device_name(BlockDriverState *bs); + int bdrv_get_flags(BlockDriverState *bs); ++int bdrv_get_max_transfer_length(BlockDriverState *bs); + int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors); + int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-iscsi-avoid-potential-overflow-of-acb-task-cdb.patch b/SOURCES/kvm-block-iscsi-avoid-potential-overflow-of-acb-task-cdb.patch index eb8cf75..bd3e9f4 100644 --- a/SOURCES/kvm-block-iscsi-avoid-potential-overflow-of-acb-task-cdb.patch +++ b/SOURCES/kvm-block-iscsi-avoid-potential-overflow-of-acb-task-cdb.patch @@ -1,16 +1,16 @@ -From f5596dffdad4014342239c7d3ec85e637969d2de Mon Sep 17 00:00:00 2001 +From d2291657a3d6100be53008fe8206c9e72b37c584 Mon Sep 17 00:00:00 2001 From: Fam Zheng -Date: Fri, 29 Jul 2016 07:54:22 +0200 +Date: Wed, 22 Jun 2016 01:06:15 +0200 Subject: [PATCH] block/iscsi: avoid potential overflow of acb->task->cdb RH-Author: Fam Zheng -Message-id: <1469778862-32607-1-git-send-email-famz@redhat.com> -Patchwork-id: 71515 -O-Subject: [RHEL-7.2.z qemu-kvm PATCH] block/iscsi: avoid potential overflow of acb->task->cdb -Bugzilla: 1358996 -RH-Acked-by: Stefan Hajnoczi -RH-Acked-by: Laszlo Ersek +Message-id: <20160622010615.10307-1-famz@redhat.com> +Patchwork-id: 70730 +O-Subject: [RHEL-7.3 qemu-kvm PATCH] block/iscsi: avoid potential overflow of acb->task->cdb +Bugzilla: 1340929 +RH-Acked-by: Miroslav Rezanina RH-Acked-by: Laurent Vivier +RH-Acked-by: Stefan Hajnoczi From: Peter Lieven diff --git a/SOURCES/kvm-block-jobs-qemu-kvm-rhel-differentiation.patch b/SOURCES/kvm-block-jobs-qemu-kvm-rhel-differentiation.patch new file mode 100644 index 0000000..c3c30e0 --- /dev/null +++ b/SOURCES/kvm-block-jobs-qemu-kvm-rhel-differentiation.patch @@ -0,0 +1,141 @@ +From bb8aca64535578520c4b7f5186f9ae5754626694 Mon Sep 17 00:00:00 2001 +From: Jeffrey Cody +Date: Thu, 5 May 2016 19:46:28 +0200 +Subject: [PATCH 10/10] block jobs: qemu-kvm-rhel differentiation + +RH-Author: Jeffrey Cody +Message-id: +Patchwork-id: 70344 +O-Subject: [RHEL7.3 qemu-kvm-rhel 1/1] block jobs: qemu-kvm-rhel differentiation +Bugzilla: 1156635 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Miroslav Rezanina + +The conditional block job disablement for RHEL left some QAPI / HMP +commands in place, that are vestigial without any actual block jobs to +control. + +This patch envelopes those block-job related functions in the +conditional code that is disabled for RHEL: + +block-job-set-speed +block-job-cancel +block-job-pause +block-job-resume +block-job-complete + +Signed-off-by: Jeff Cody +Signed-off-by: Miroslav Rezanina +--- + blockdev.c | 2 +- + hmp-commands.hx | 2 +- + hmp.c | 2 +- + qapi-schema.json | 2 +- + qmp-commands.hx | 3 --- + 5 files changed, 4 insertions(+), 7 deletions(-) + +diff --git a/blockdev.c b/blockdev.c +index b5792a2..69e951f 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -1701,7 +1701,6 @@ void qmp_drive_mirror(const char *device, const char *target, + return; + } + } +-#endif + + static BlockJob *find_block_job(const char *device) + { +@@ -1786,6 +1785,7 @@ void qmp_block_job_complete(const char *device, Error **errp) + trace_qmp_block_job_complete(job); + block_job_complete(job, errp); + } ++#endif + + void qmp___com_redhat_change_backing_file(const char *device, + const char *image_node_name, +diff --git a/hmp-commands.hx b/hmp-commands.hx +index 7e1855a..dd528d2 100644 +--- a/hmp-commands.hx ++++ b/hmp-commands.hx +@@ -81,7 +81,6 @@ ETEXI + .help = "copy data from a backing file into a block device", + .mhandler.cmd = hmp_block_stream, + }, +-#endif + + STEXI + @item block_stream +@@ -160,6 +159,7 @@ STEXI + @findex block_job_resume + Resume a paused block streaming operation. + ETEXI ++#endif + + { + .name = "eject", +diff --git a/hmp.c b/hmp.c +index e1d92f4..fb9b445 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -1053,7 +1053,6 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict) + + hmp_handle_error(mon, &error); + } +-#endif + + void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict) + { +@@ -1106,6 +1105,7 @@ void hmp_block_job_complete(Monitor *mon, const QDict *qdict) + + hmp_handle_error(mon, &error); + } ++#endif + + typedef struct MigrationStatus + { +diff --git a/qapi-schema.json b/qapi-schema.json +index c8732c1..5138ed9 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -2326,7 +2326,6 @@ + { 'command': 'block-stream', + 'data': { 'device': 'str', '*base': 'str', '*backing-file': 'str', + '*speed': 'int', '*on-error': 'BlockdevOnError' } } +-#_end-rhev-only + + ## + # @block-job-set-speed: +@@ -2448,6 +2447,7 @@ + # Since: 1.3 + ## + { 'command': 'block-job-complete', 'data': { 'device': 'str' } } ++#_end-rhev-only + + ## + # @ObjectTypeInfo: +diff --git a/qmp-commands.hx b/qmp-commands.hx +index 22a09be..9522c44 100644 +--- a/qmp-commands.hx ++++ b/qmp-commands.hx +@@ -1089,8 +1089,6 @@ Example: + + EQMP + +-#endif +- + { + .name = "block-job-set-speed", + .args_type = "device:B,speed:o", +@@ -1117,7 +1115,6 @@ EQMP + .args_type = "device:B", + .mhandler.cmd_new = qmp_marshal_input_block_job_complete, + }, +-#ifdef CONFIG_LIVE_BLOCK_OPS + { + .name = "transaction", + .args_type = "actions:q", +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-raw-posix-Open-file-descriptor-O_RDWR-to-work-.patch b/SOURCES/kvm-block-raw-posix-Open-file-descriptor-O_RDWR-to-work-.patch new file mode 100644 index 0000000..fc8ca11 --- /dev/null +++ b/SOURCES/kvm-block-raw-posix-Open-file-descriptor-O_RDWR-to-work-.patch @@ -0,0 +1,68 @@ +From 9452583824b50cb6f095c5ec1894b38df7b01175 Mon Sep 17 00:00:00 2001 +Message-Id: <9452583824b50cb6f095c5ec1894b38df7b01175.1464449390.git.jen@redhat.com> +In-Reply-To: +References: +From: Kevin Wolf +Date: Mon, 23 May 2016 11:28:41 -0400 +Subject: [CHANGE 3/3] block/raw-posix: Open file descriptor O_RDWR to work + around glibc posix_fallocate emulation issue. +To: rhvirt-patches@redhat.com, + jen@redhat.com + +RH-Author: Kevin Wolf +Message-id: <1464002921-1079-2-git-send-email-kwolf@redhat.com> +Patchwork-id: 70425 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/1] block/raw-posix: Open file descriptor O_RDWR to work around glibc posix_fallocate emulation issue. +Bugzilla: 1268345 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Richard Jones + +From: "Richard W.M. Jones" + +The following command fails on an NFS mountpoint: + + $ qemu-img create -f qcow2 -o preallocation=falloc disk.img 262144 + Formatting 'disk.img', fmt=qcow2 size=262144 encryption=off cluster_size=65536 preallocation='falloc' lazy_refcounts=off + qemu-img: disk.img: Could not preallocate data for the new file: Bad file descriptor + +The reason turns out to be because NFS doesn't support the +posix_fallocate call. glibc emulates it instead. However glibc's +emulation involves using the pread(2) syscall. The pread syscall +fails with EBADF if the file descriptor is opened without the read +open-flag (ie. open (..., O_WRONLY)). + +I contacted glibc upstream about this, and their response is here: + + https://bugzilla.redhat.com/show_bug.cgi?id=1265196#c9 + +There are two possible fixes: Use Linux fallocate directly, or (this +fix) work around the problem in qemu by opening the file with O_RDWR +instead of O_WRONLY. + +Signed-off-by: Richard W.M. Jones +Reviewed-by: Jeff Cody +Reviewed-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit 73ba05d936e82fe01b2b2cf987bf3aecb4792af5) +Signed-off-by: Jeff E. Nelson +--- + block/raw-posix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/raw-posix.c b/block/raw-posix.c +index 1f5275f..92fcb6c 100644 +--- a/block/raw-posix.c ++++ b/block/raw-posix.c +@@ -1265,7 +1265,7 @@ static int raw_create(const char *filename, QEMUOptionParameter *options, + options++; + } + +- fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, ++ fd = qemu_open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + 0644); + if (fd < 0) { + result = -errno; +-- +2.5.5 + diff --git a/SOURCES/kvm-block-vmdk-fixed-sizeof-error.patch b/SOURCES/kvm-block-vmdk-fixed-sizeof-error.patch new file mode 100644 index 0000000..34c517c --- /dev/null +++ b/SOURCES/kvm-block-vmdk-fixed-sizeof-error.patch @@ -0,0 +1,50 @@ +From 37bf9db781d9507501649ee04d23b0dab103a126 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:23 +0100 +Subject: [PATCH 10/18] block: vmdk - fixed sizeof() error + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-11-git-send-email-famz@redhat.com> +Patchwork-id: 69176 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 10/18] block: vmdk - fixed sizeof() error +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +From: Jeff Cody + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +The size compared should be PATH_MAX, rather than sizeof(char *). + +Reported-by: Paolo Bonzini +Signed-off-by: Jeff Cody +Reviewed-by: Eric Blake +Reviewed-by: Max Reitz +Message-id: 46d873261433f4527e88885582f96942d61758d6.1423592487.git.jcody@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit a7be17bee855f26c317e99aa6582e1dc9b8ebd71) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 45ecf02..32b3d4c 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -838,8 +838,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, + } + + extent_path = g_malloc0(PATH_MAX); +- path_combine(extent_path, sizeof(extent_path), +- desc_file_path, fname); ++ path_combine(extent_path, PATH_MAX, desc_file_path, fname); + extent_file = NULL; + ret = bdrv_file_open(&extent_file, extent_path, NULL, bs->open_flags, + errp); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-vmdk-make-ret-variable-usage-clear.patch b/SOURCES/kvm-block-vmdk-make-ret-variable-usage-clear.patch new file mode 100644 index 0000000..afc092c --- /dev/null +++ b/SOURCES/kvm-block-vmdk-make-ret-variable-usage-clear.patch @@ -0,0 +1,86 @@ +From 931d28d0c1c1015df16fbffb8422895497193a78 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:21 +0100 +Subject: [PATCH 08/18] block: vmdk - make ret variable usage clear + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-9-git-send-email-famz@redhat.com> +Patchwork-id: 69174 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 08/18] block: vmdk - make ret variable usage clear +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +From: Jeff Cody + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +Keep the variable 'ret' something that is returned by the function it is +defined in. For the return value of 'sscanf', use a more meaningful +variable name. + +Reviewed-by: Stefan Hajnoczi +Reviewed-by: John Snow +Signed-off-by: Jeff Cody +Signed-off-by: Kevin Wolf +(cherry picked from commit 395a22fae064df64d987d703cf70ae0f57306be8) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 1247ea4..3351782 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -788,6 +788,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, + const char *desc_file_path, Error **errp) + { + int ret; ++ int matches; + char access[11]; + char type[11]; + char fname[512]; +@@ -799,6 +800,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, + BDRVVmdkState *s = bs->opaque; + VmdkExtent *extent; + ++ + while (*p) { + /* parse extent line in one of below formats: + * +@@ -808,23 +810,23 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, + * RW [size in sectors] VMFSSPARSE "file-name.vmdk" + */ + flat_offset = -1; +- ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, +- access, §ors, type, fname, &flat_offset); +- if (ret < 4 || strcmp(access, "RW")) { ++ matches = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, ++ access, §ors, type, fname, &flat_offset); ++ if (matches < 4 || strcmp(access, "RW")) { + goto next_line; + } else if (!strcmp(type, "FLAT")) { +- if (ret != 5 || flat_offset < 0) { ++ if (matches != 5 || flat_offset < 0) { + error_setg(errp, "Invalid extent lines: \n%s", p); + return -EINVAL; + } + } else if (!strcmp(type, "VMFS")) { +- if (ret == 4) { ++ if (matches == 4) { + flat_offset = 0; + } else { + error_setg(errp, "Invalid extent lines:\n%s", p); + return -EINVAL; + } +- } else if (ret != 4) { ++ } else if (matches != 4) { + error_setg(errp, "Invalid extent lines:\n%s", p); + return -EINVAL; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-block-vmdk-move-string-allocations-from-stack-to-the.patch b/SOURCES/kvm-block-vmdk-move-string-allocations-from-stack-to-the.patch new file mode 100644 index 0000000..e1d5c95 --- /dev/null +++ b/SOURCES/kvm-block-vmdk-move-string-allocations-from-stack-to-the.patch @@ -0,0 +1,146 @@ +From a767838caf6c761d714a9466d008f8dddaf1a162 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:22 +0100 +Subject: [PATCH 09/18] block: vmdk - move string allocations from stack to the + heap + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-10-git-send-email-famz@redhat.com> +Patchwork-id: 69175 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 09/18] block: vmdk - move string allocations from stack to the heap +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +From: Jeff Cody + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +Functions 'vmdk_parse_extents' and 'vmdk_create' allocate several +PATH_MAX sized arrays on the stack. Make these dynamically allocated. + +Signed-off-by: Jeff Cody +Signed-off-by: Kevin Wolf +(cherry picked from commit fe2065629a9c256f836770ca54449ae77b22d188) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 40 ++++++++++++++++++++++++---------------- + 1 file changed, 24 insertions(+), 16 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 3351782..45ecf02 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -795,12 +795,11 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, + const char *p = desc; + int64_t sectors = 0; + int64_t flat_offset; +- char extent_path[PATH_MAX]; ++ char *extent_path; + BlockDriverState *extent_file; + BDRVVmdkState *s = bs->opaque; + VmdkExtent *extent; + +- + while (*p) { + /* parse extent line in one of below formats: + * +@@ -838,10 +837,13 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, + goto next_line; + } + ++ extent_path = g_malloc0(PATH_MAX); + path_combine(extent_path, sizeof(extent_path), + desc_file_path, fname); ++ extent_file = NULL; + ret = bdrv_file_open(&extent_file, extent_path, NULL, bs->open_flags, + errp); ++ g_free(extent_path); + if (ret) { + return ret; + } +@@ -1790,10 +1792,15 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, + int ret = 0; + bool flat, split, compress; + GString *ext_desc_lines; +- char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX]; ++ char *path = g_malloc0(PATH_MAX); ++ char *prefix = g_malloc0(PATH_MAX); ++ char *postfix = g_malloc0(PATH_MAX); ++ char *desc_line = g_malloc0(BUF_SIZE); ++ char *ext_filename = g_malloc0(PATH_MAX); ++ char *desc_filename = g_malloc0(PATH_MAX); + const int64_t split_size = 0x80000000; /* VMDK has constant split size */ + const char *desc_extent_line; +- char parent_desc_line[BUF_SIZE] = ""; ++ char *parent_desc_line = g_malloc0(BUF_SIZE); + uint32_t parent_cid = 0xffffffff; + uint32_t number_heads = 16; + bool zeroed_grain = false; +@@ -1902,33 +1909,27 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, + } + parent_cid = vmdk_read_cid(bs, 0); + bdrv_unref(bs); +- snprintf(parent_desc_line, sizeof(parent_desc_line), ++ snprintf(parent_desc_line, BUF_SIZE, + "parentFileNameHint=\"%s\"", backing_file); + } + + /* Create extents */ + filesize = total_size; + while (filesize > 0) { +- char desc_line[BUF_SIZE]; +- char ext_filename[PATH_MAX]; +- char desc_filename[PATH_MAX]; + int64_t size = filesize; + + if (split && size > split_size) { + size = split_size; + } + if (split) { +- snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s", ++ snprintf(desc_filename, PATH_MAX, "%s-%c%03d%s", + prefix, flat ? 'f' : 's', ++idx, postfix); + } else if (flat) { +- snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s", +- prefix, postfix); ++ snprintf(desc_filename, PATH_MAX, "%s-flat%s", prefix, postfix); + } else { +- snprintf(desc_filename, sizeof(desc_filename), "%s%s", +- prefix, postfix); ++ snprintf(desc_filename, PATH_MAX, "%s%s", prefix, postfix); + } +- snprintf(ext_filename, sizeof(ext_filename), "%s%s", +- path, desc_filename); ++ snprintf(ext_filename, PATH_MAX, "%s%s", path, desc_filename); + + if (vmdk_create_extent(ext_filename, size, + flat, compress, zeroed_grain, errp)) { +@@ -1938,7 +1939,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, + filesize -= size; + + /* Format description line */ +- snprintf(desc_line, sizeof(desc_line), ++ snprintf(desc_line, BUF_SIZE, + desc_extent_line, size / BDRV_SECTOR_SIZE, desc_filename); + g_string_append(ext_desc_lines, desc_line); + } +@@ -1988,6 +1989,13 @@ exit: + bdrv_unref(new_bs); + } + g_free(desc); ++ g_free(path); ++ g_free(prefix); ++ g_free(postfix); ++ g_free(desc_line); ++ g_free(ext_filename); ++ g_free(desc_filename); ++ g_free(parent_desc_line); + g_string_free(ext_desc_lines, true); + return ret; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-check-qjson-Add-test-for-JSON-nesting-depth-limit.patch b/SOURCES/kvm-check-qjson-Add-test-for-JSON-nesting-depth-limit.patch new file mode 100644 index 0000000..aac6412 --- /dev/null +++ b/SOURCES/kvm-check-qjson-Add-test-for-JSON-nesting-depth-limit.patch @@ -0,0 +1,73 @@ +From 38d4fe12ad2e3bc18842201f437c480120eace2b Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:02 +0200 +Subject: [PATCH 04/16] check-qjson: Add test for JSON nesting depth limit + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-6-git-send-email-armbru@redhat.com> +Patchwork-id: 71481 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 04/15] check-qjson: Add test for JSON nesting depth limit +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +This would have prevented the regression mentioned in the previous +commit. + +Signed-off-by: Markus Armbruster +Reviewed-by: Eric Blake +Message-Id: <1448486613-17634-4-git-send-email-armbru@redhat.com> +(cherry picked from commit f0ae0304c7a41a42b7d4a6cde450da938d3c2cc7) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + tests/check-qjson.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +diff --git a/tests/check-qjson.c b/tests/check-qjson.c +index 4e74548..c5dd74d 100644 +--- a/tests/check-qjson.c ++++ b/tests/check-qjson.c +@@ -1465,6 +1465,30 @@ static void unterminated_literal(void) + g_assert(obj == NULL); + } + ++static char *make_nest(char *buf, size_t cnt) ++{ ++ memset(buf, '[', cnt - 1); ++ buf[cnt - 1] = '{'; ++ buf[cnt] = '}'; ++ memset(buf + cnt + 1, ']', cnt - 1); ++ buf[2 * cnt] = 0; ++ return buf; ++} ++ ++static void limits_nesting(void) ++{ ++ enum { max_nesting = 1024 }; /* see qobject/json-streamer.c */ ++ char buf[2 * (max_nesting + 1) + 1]; ++ QObject *obj; ++ ++ obj = qobject_from_json(make_nest(buf, max_nesting)); ++ g_assert(obj != NULL); ++ qobject_decref(obj); ++ ++ obj = qobject_from_json(make_nest(buf, max_nesting + 1)); ++ g_assert(obj == NULL); ++} ++ + int main(int argc, char **argv) + { + g_test_init(&argc, &argv, NULL); +@@ -1500,6 +1524,7 @@ int main(int argc, char **argv) + g_test_add_func("/errors/invalid_array_comma", invalid_array_comma); + g_test_add_func("/errors/invalid_dict_comma", invalid_dict_comma); + g_test_add_func("/errors/unterminated/literal", unterminated_literal); ++ g_test_add_func("/errors/limits/nesting", limits_nesting); + + return g_test_run(); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-cutils-Support-P-and-E-suffixes-in-strtosz.patch b/SOURCES/kvm-cutils-Support-P-and-E-suffixes-in-strtosz.patch new file mode 100644 index 0000000..d5937c8 --- /dev/null +++ b/SOURCES/kvm-cutils-Support-P-and-E-suffixes-in-strtosz.patch @@ -0,0 +1,132 @@ +From b7cea737b24456765a21ed43ebd9b68ebbbf3537 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:21 +0100 +Subject: [PATCH 02/27] cutils: Support 'P' and 'E' suffixes in strtosz() + +RH-Author: John Snow +Message-id: <1448300320-7772-3-git-send-email-jsnow@redhat.com> +Patchwork-id: 68430 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 02/21] cutils: Support 'P' and 'E' suffixes in strtosz() +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 5e00984aef7c1c317e27c0e8acf66526513c770f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + include/qemu-common.h | 2 ++ + monitor.c | 8 ++++---- + qemu-img.c | 10 ++++++---- + tests/qemu-iotests/049.out | 8 ++++---- + util/cutils.c | 4 ++++ + 5 files changed, 20 insertions(+), 12 deletions(-) + +diff --git a/include/qemu-common.h b/include/qemu-common.h +index aee85e3..67f57c9 100644 +--- a/include/qemu-common.h ++++ b/include/qemu-common.h +@@ -178,6 +178,8 @@ int parse_uint_full(const char *s, unsigned long long *value, int base); + * A-Z, as strtosz() will use qemu_toupper() on the given argument + * prior to comparison. + */ ++#define STRTOSZ_DEFSUFFIX_EB 'E' ++#define STRTOSZ_DEFSUFFIX_PB 'P' + #define STRTOSZ_DEFSUFFIX_TB 'T' + #define STRTOSZ_DEFSUFFIX_GB 'G' + #define STRTOSZ_DEFSUFFIX_MB 'M' +diff --git a/monitor.c b/monitor.c +index 6a1d06e..33c5bc8 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -94,10 +94,10 @@ + * 'M' Non-negative target long (32 or 64 bit), in user mode the + * value is multiplied by 2^20 (think Mebibyte) + * 'o' octets (aka bytes) +- * user mode accepts an optional T, t, G, g, M, m, K, k +- * suffix, which multiplies the value by 2^40 for +- * suffixes T and t, 2^30 for suffixes G and g, 2^20 for +- * M and m, 2^10 for K and k ++ * user mode accepts an optional E, e, P, p, T, t, G, g, M, m, ++ * K, k suffix, which multiplies the value by 2^60 for suffixes E ++ * and e, 2^50 for suffixes P and p, 2^40 for suffixes T and t, ++ * 2^30 for suffixes G and g, 2^20 for M and m, 2^10 for K and k + * 'T' double + * user mode accepts an optional ms, us, ns suffix, + * which divides the value by 1e3, 1e6, 1e9, respectively +diff --git a/qemu-img.c b/qemu-img.c +index 9c021e7..eb2d4cb 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -87,8 +87,9 @@ static void help(void) + " 'src_cache' is the cache mode used to read input disk images, the valid\n" + " options are the same as for the 'cache' option\n" + " 'size' is the disk image size in bytes. Optional suffixes\n" +- " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n" +- " and T (terabyte, 1024G) are supported. 'b' is ignored.\n" ++ " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M),\n" ++ " 'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 1024P) are\n" ++ " supported. 'b' is ignored.\n" + " 'output_filename' is the destination disk image filename\n" + " 'output_fmt' is the destination format\n" + " 'options' is a comma separated list of format specific options in a\n" +@@ -417,8 +418,9 @@ static int img_create(int argc, char **argv) + error_report("Image size must be less than 8 EiB!"); + } else { + error_report("Invalid image size specified! You may use k, M, " +- "G or T suffixes for "); +- error_report("kilobytes, megabytes, gigabytes and terabytes."); ++ "G, T, P or E suffixes for "); ++ error_report("kilobytes, megabytes, gigabytes, terabytes, " ++ "petabytes and exabytes."); + } + goto fail; + } +diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out +index b2fcf0b..3e56772 100644 +--- a/tests/qemu-iotests/049.out ++++ b/tests/qemu-iotests/049.out +@@ -108,15 +108,15 @@ qemu-img: TEST_DIR/t.qcow2: Could not resize image: Operation not supported + Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte +-qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for +-qemu-img: kilobytes, megabytes, gigabytes and terabytes. ++qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for ++qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes. + + qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2 + Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off + + qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar +-qemu-img: Invalid image size specified! You may use k, M, G or T suffixes for +-qemu-img: kilobytes, megabytes, gigabytes and terabytes. ++qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for ++qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes. + + qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2 + qemu-img: Parameter 'size' expects a size +diff --git a/util/cutils.c b/util/cutils.c +index a165819..8f28896 100644 +--- a/util/cutils.c ++++ b/util/cutils.c +@@ -267,6 +267,10 @@ static int64_t suffix_mul(char suffix, int64_t unit) + return unit * unit * unit; + case STRTOSZ_DEFSUFFIX_TB: + return unit * unit * unit * unit; ++ case STRTOSZ_DEFSUFFIX_PB: ++ return unit * unit * unit * unit * unit; ++ case STRTOSZ_DEFSUFFIX_EB: ++ return unit * unit * unit * unit * unit * unit; + } + return -1; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch b/SOURCES/kvm-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch new file mode 100644 index 0000000..41398a8 --- /dev/null +++ b/SOURCES/kvm-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch @@ -0,0 +1,109 @@ +From 4fef3479339001ef3ea529fb0552533fae422240 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Fri, 5 Feb 2016 14:26:18 +0100 +Subject: [PATCH 1/5] e1000: eliminate infinite loops on out-of-bounds transfer + start + +RH-Author: Laszlo Ersek +Message-id: <1454682378-29144-2-git-send-email-lersek@redhat.com> +Patchwork-id: 69116 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/1] e1000: eliminate infinite loops on out-of-bounds transfer start +Bugzilla: 1296044 +RH-Acked-by: Xiao Wang +RH-Acked-by: P J P +RH-Acked-by: Stefan Hajnoczi + +The start_xmit() and e1000_receive_iov() functions implement DMA transfers +iterating over a set of descriptors that the guest's e1000 driver +prepares: + +- the TDLEN and RDLEN registers store the total size of the descriptor + area, + +- while the TDH and RDH registers store the offset (in whole tx / rx + descriptors) into the area where the transfer is supposed to start. + +Each time a descriptor is processed, the TDH and RDH register is bumped +(as appropriate for the transfer direction). + +QEMU already contains logic to deal with bogus transfers submitted by the +guest: + +- Normally, the transmit case wants to increase TDH from its initial value + to TDT. (TDT is allowed to be numerically smaller than the initial TDH + value; wrapping at or above TDLEN bytes to zero is normal.) The failsafe + that QEMU currently has here is a check against reaching the original + TDH value again -- a complete wraparound, which should never happen. + +- In the receive case RDH is increased from its initial value until + "total_size" bytes have been received; preferably in a single step, or + in "s->rxbuf_size" byte steps, if the latter is smaller. However, null + RX descriptors are skipped without receiving data, while RDH is + incremented just the same. QEMU tries to prevent an infinite loop + (processing only null RX descriptors) by detecting whether RDH assumes + its original value during the loop. (Again, wrapping from RDLEN to 0 is + normal.) + +What both directions miss is that the guest could program TDLEN and RDLEN +so low, and the initial TDH and RDH so high, that these registers will +immediately be truncated to zero, and then never reassume their initial +values in the loop -- a full wraparound will never occur. + +The condition that expresses this is: + + xdh_start >= s->mac_reg[XDLEN] / sizeof(desc) + +i.e., TDH or RDH start out after the last whole rx or tx descriptor that +fits into the TDLEN or RDLEN sized area. + +This condition could be checked before we enter the loops, but +pci_dma_read() / pci_dma_write() knows how to fill in buffers safely for +bogus DMA addresses, so we just extend the existing failsafes with the +above condition. + +This is CVE-2016-1981. + +Cc: "Michael S. Tsirkin" +Cc: Petr Matousek +Cc: Stefano Stabellini +Cc: Prasad Pandit +Cc: Michael Roth +Cc: Jason Wang +Cc: qemu-stable@nongnu.org +RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1296044 +Signed-off-by: Laszlo Ersek +Reviewed-by: Jason Wang +Signed-off-by: Jason Wang +(cherry picked from commit dd793a74882477ca38d49e191110c17dfee51dcc) +Signed-off-by: Miroslav Rezanina +--- + hw/net/e1000.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/net/e1000.c b/hw/net/e1000.c +index 87a84a7..2cd38bc 100644 +--- a/hw/net/e1000.c ++++ b/hw/net/e1000.c +@@ -697,7 +697,8 @@ start_xmit(E1000State *s) + * bogus values to TDT/TDLEN. + * there's nothing too intelligent we could do about this. + */ +- if (s->mac_reg[TDH] == tdh_start) { ++ if (s->mac_reg[TDH] == tdh_start || ++ tdh_start >= s->mac_reg[TDLEN] / sizeof(desc)) { + DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n", + tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]); + break; +@@ -902,7 +903,8 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) + if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN]) + s->mac_reg[RDH] = 0; + /* see comment in start_xmit; same here */ +- if (s->mac_reg[RDH] == rdh_start) { ++ if (s->mac_reg[RDH] == rdh_start || ++ rdh_start >= s->mac_reg[RDLEN] / sizeof(desc)) { + DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n", + rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]); + set_ics(s, 0, E1000_ICS_RXO); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ehci-clear-suspend-bit-on-detach.patch b/SOURCES/kvm-ehci-clear-suspend-bit-on-detach.patch new file mode 100644 index 0000000..9a38ccd --- /dev/null +++ b/SOURCES/kvm-ehci-clear-suspend-bit-on-detach.patch @@ -0,0 +1,48 @@ +From ad3f6b5b188c572bd07cc5929e844138c2d95915 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 13 Nov 2015 13:32:34 +0100 +Subject: [PATCH 1/6] ehci: clear suspend bit on detach + +Message-id: <1447421554-28366-2-git-send-email-kraxel@redhat.com> +Patchwork-id: 68349 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/1] ehci: clear suspend bit on detach +Bugzilla: 1268879 +RH-Acked-by: Markus Armbruster +RH-Acked-by: John Snow +RH-Acked-by: Laszlo Ersek + +When a device is detached, clear the suspend bit (PORTSC_SUSPEND) +in the port status register. + +The specs are not *that* clear what is supposed to happen in case +a suspended device is unplugged. But the enable bit (PORTSC_PED) +is cleared, and the specs mention setting suspend with enable being +unset is undefined behavior. So clearing them both looks reasonable, +and it actually fixes the reported bug. + +Cc: Hans de Goede +Signed-off-by: Gerd Hoffmann +Reviewed-by: Hans de Goede +Message-id: 1445413462-18004-1-git-send-email-kraxel@redhat.com +(cherry picked from commit cbf82fa01e6fd4ecb234b235b10ffce548154a95) +Signed-off-by: Miroslav Rezanina +--- + hw/usb/hcd-ehci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 02d2ab7..3429c77 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -802,7 +802,7 @@ static void ehci_detach(USBPort *port) + ehci_queues_rip_device(s, port->dev, 0); + ehci_queues_rip_device(s, port->dev, 1); + +- *portsc &= ~(PORTSC_CONNECT|PORTSC_PED); ++ *portsc &= ~(PORTSC_CONNECT|PORTSC_PED|PORTSC_SUSPEND); + *portsc |= PORTSC_CSC; + + ehci_raise_irq(s, USBSTS_PCD); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-fw_cfg-add-check-to-validate-current-entry-value-CVE.patch b/SOURCES/kvm-fw_cfg-add-check-to-validate-current-entry-value-CVE.patch index e1eb3b2..ac3c08f 100644 --- a/SOURCES/kvm-fw_cfg-add-check-to-validate-current-entry-value-CVE.patch +++ b/SOURCES/kvm-fw_cfg-add-check-to-validate-current-entry-value-CVE.patch @@ -1,16 +1,17 @@ -From 5d12c17191e042a57e02749cedc55104a8251ac3 Mon Sep 17 00:00:00 2001 +From ba24567fd90702ea40ff320a79bc921b38510f22 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Thu, 21 Jan 2016 07:17:43 +0100 -Subject: [PATCH] fw_cfg: add check to validate current entry value +Subject: [PATCH 2/2] fw_cfg: add check to validate current entry value (CVE-2016-1714) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit +RH-Author: Miroslav Rezanina Message-id: <1453360663-5066-1-git-send-email-mrezanin@redhat.com> Patchwork-id: 68834 O-Subject: [RHEL-7.2.z/RHEL-7.3 qemu-kvm PATCH] fw_cfg: add check to validate current entry value (CVE-2016-1714) -Bugzilla: 1298047 +Bugzilla: 1298048 RH-Acked-by: Laurent Vivier RH-Acked-by: Laszlo Ersek RH-Acked-by: Gerd Hoffmann diff --git a/SOURCES/kvm-hw-input-hid.c-Fix-capslock-hid-code.patch b/SOURCES/kvm-hw-input-hid.c-Fix-capslock-hid-code.patch new file mode 100644 index 0000000..4a15536 --- /dev/null +++ b/SOURCES/kvm-hw-input-hid.c-Fix-capslock-hid-code.patch @@ -0,0 +1,50 @@ +From 61ecb3c995018bc9ec901d376004c1d092d166ff Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 1 Jun 2016 12:24:01 +0200 +Subject: [PATCH 1/3] hw/input/hid.c Fix capslock hid code + +RH-Author: Gerd Hoffmann +Message-id: <1464783841-27701-2-git-send-email-kraxel@redhat.com> +Patchwork-id: 70522 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/1] hw/input/hid.c Fix capslock hid code +Bugzilla: 1256741 +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Dr. David Alan Gilbert +RH-Acked-by: Thomas Huth + +From: Dinar Valeev + +When ever USB keyboard is used, e.g. '-usbdevice keyboard' pressing +caps lock key send 0x32 hid code, which is treated as backslash. +Instead it should be 0x39 code. This affects sending uppercase keys, +as they typed whith caps lock active. + +While on x86 this can be workarounded by using ps/2 protocol. On +Power it is crusial as we don't have anything else than USB. + +This is fixes guest automation tasts over vnc. + +Signed-off-by: Dinar Valeev +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 0ee4de5840ccc1072459ec68062bfb63c888a94d) +Signed-off-by: Miroslav Rezanina +--- + hw/input/hid.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/input/hid.c b/hw/input/hid.c +index 14b3125..db45c89 100644 +--- a/hw/input/hid.c ++++ b/hw/input/hid.c +@@ -41,7 +41,7 @@ static const uint8_t hid_usage_keys[0x100] = { + 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, + 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19, + 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, +- 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, ++ 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, + 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, + 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-ide-test-fix-failure-for-test_flush.patch b/SOURCES/kvm-ide-test-fix-failure-for-test_flush.patch new file mode 100644 index 0000000..d7e4c96 --- /dev/null +++ b/SOURCES/kvm-ide-test-fix-failure-for-test_flush.patch @@ -0,0 +1,113 @@ +From 31ce74359a069be69af0f6ba2f7867ed2083317a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Tue, 8 Dec 2015 20:30:59 +0100 +Subject: [PATCH 21/27] ide-test: fix failure for test_flush + +RH-Author: John Snow +Message-id: <1449606659-23710-1-git-send-email-jsnow@redhat.com> +Patchwork-id: 68521 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v3 21/21] ide-test: fix failure for test_flush +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +This patch is a combination of two patches: + +(1) Revert "qtest/ide-test: disable flush-test" +(2) ide-test: fix failure for test_flush + +First, the downstream-only revert: +This reverts commit 228e49fabffa644ab7a6a03e98205f293115dc89. + +Second, the backported fix: + +bd07684aacfb61668ae2c25b7dd00b64f3d7c7f3 added a test to ensure BSY +flag is set when a flush request is in flight. It does this by setting +a blkdebug breakpoint on flush_to_os before issuing a CMD_FLUSH_CACHE. +It then resumes CMD_FLUSH_CACHE operation and checks that BSY is unset. + +The actual unsetting of BSY does not occur until ide_flush_cb gets +called in a bh, however, so in some cases this check will race with +the actual completion. + +Fix this by polling the ide status register until BSY flag gets unset +before we do our final sanity checks. According to +f68ec8379e88502b4841a110c070e9b118d3151c this is in line with how a guest +would determine whether or not the device is still busy. + +Signed-off-by: Michael Roth +Signed-off-by: Anthony Liguori +(cherry picked from commit 22bfa16ed3d4c9d534dcfe6f2381a654f32296b9) +Signed-off-by: John Snow +--- + tests/ide-test.c | 41 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +Signed-off-by: Miroslav Rezanina +--- + tests/ide-test.c | 41 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/tests/ide-test.c b/tests/ide-test.c +index 43b7fd6..92dd0e5 100644 +--- a/tests/ide-test.c ++++ b/tests/ide-test.c +@@ -425,6 +425,46 @@ static void test_identify(void) + ide_test_quit(); + } + ++static void test_flush(void) ++{ ++ uint8_t data; ++ ++ ide_test_start( ++ "-vnc none " ++ "-drive file=blkdebug::%s,if=ide,cache=writeback", ++ tmp_path); ++ ++ /* Delay the completion of the flush request until we explicitly do it */ ++ qmp("{'execute':'human-monitor-command', 'arguments': { " ++ "'command-line': 'qemu-io ide0-hd0 \"break flush_to_os A\"'} }"); ++ ++ /* FLUSH CACHE command on device 0*/ ++ outb(IDE_BASE + reg_device, 0); ++ outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE); ++ ++ /* Check status while request is in flight*/ ++ data = inb(IDE_BASE + reg_status); ++ assert_bit_set(data, BSY | DRDY); ++ assert_bit_clear(data, DF | ERR | DRQ); ++ ++ /* Complete the command */ ++ qmp("{'execute':'human-monitor-command', 'arguments': { " ++ "'command-line': 'qemu-io ide0-hd0 \"resume A\"'} }"); ++ ++ /* Check registers */ ++ data = inb(IDE_BASE + reg_device); ++ g_assert_cmpint(data & DEV, ==, 0); ++ ++ do { ++ data = inb(IDE_BASE + reg_status); ++ } while (data & BSY); ++ ++ assert_bit_set(data, DRDY); ++ assert_bit_clear(data, BSY | DF | ERR | DRQ); ++ ++ ide_test_quit(); ++} ++ + static void test_flush_nodev(void) + { + ide_test_start(""); +@@ -468,6 +508,7 @@ int main(int argc, char **argv) + qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt); + qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown); + ++ qtest_add_func("/ide/flush", test_flush); + qtest_add_func("/ide/flush_nodev", test_flush_nodev); + + ret = g_test_run(); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-json-parser-drop-superfluous-assignment-for-token-va.patch b/SOURCES/kvm-json-parser-drop-superfluous-assignment-for-token-va.patch new file mode 100644 index 0000000..3e6503f --- /dev/null +++ b/SOURCES/kvm-json-parser-drop-superfluous-assignment-for-token-va.patch @@ -0,0 +1,97 @@ +From 110f5902133db4e8a46c9cc18ed0d4ed2e99aec2 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:34:59 +0200 +Subject: [PATCH 01/16] json-parser: drop superfluous assignment for token + variable + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-3-git-send-email-armbru@redhat.com> +Patchwork-id: 71470 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 01/15] json-parser: drop superfluous assignment for token variable +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Gonglei + +Signed-off-by: ChenLiang +Signed-off-by: Gonglei +Reviewed-by: Eric Blake +Reviewed-by: Paolo Bonzini +Signed-off-by: Luiz Capitulino +(cherry picked from commit a491af471bf8f1188b2665f54d109065d4591e45) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + qobject/json-parser.c | 15 ++------------- + 1 file changed, 2 insertions(+), 13 deletions(-) + +diff --git a/qobject/json-parser.c b/qobject/json-parser.c +index e7947b3..fa09769 100644 +--- a/qobject/json-parser.c ++++ b/qobject/json-parser.c +@@ -423,7 +423,6 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + if (!token_is_operator(token, '{')) { + goto out; + } +- token = NULL; + + dict = qdict_new(); + +@@ -449,7 +448,6 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + parse_error(ctxt, token, "expected separator in dict"); + goto out; + } +- token = NULL; + + if (parse_pair(ctxt, dict, ap) == -1) { + goto out; +@@ -461,10 +459,8 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + goto out; + } + } +- token = NULL; + } else { +- token = parser_context_pop_token(ctxt); +- token = NULL; ++ (void)parser_context_pop_token(ctxt); + } + + return QOBJECT(dict); +@@ -487,10 +483,8 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + } + + if (!token_is_operator(token, '[')) { +- token = NULL; + goto out; + } +- token = NULL; + + list = qlist_new(); + +@@ -523,8 +517,6 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- token = NULL; +- + obj = parse_value(ctxt, ap); + if (obj == NULL) { + parse_error(ctxt, token, "expecting value"); +@@ -539,11 +531,8 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + goto out; + } + } +- +- token = NULL; + } else { +- token = parser_context_pop_token(ctxt); +- token = NULL; ++ (void)parser_context_pop_token(ctxt); + } + + return QOBJECT(list); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-json-streamer-Don-t-leak-tokens-on-incomplete-parse.patch b/SOURCES/kvm-json-streamer-Don-t-leak-tokens-on-incomplete-parse.patch new file mode 100644 index 0000000..73a78fd --- /dev/null +++ b/SOURCES/kvm-json-streamer-Don-t-leak-tokens-on-incomplete-parse.patch @@ -0,0 +1,65 @@ +From b3e87d63aec8631b853cb86a0736af41954769a4 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:12 +0200 +Subject: [PATCH 14/16] json-streamer: Don't leak tokens on incomplete parse + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-16-git-send-email-armbru@redhat.com> +Patchwork-id: 71477 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 14/15] json-streamer: Don't leak tokens on incomplete parse +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Eric Blake + +Valgrind complained about a number of leaks in +tests/check-qobject-json: + +==12657== definitely lost: 17,247 bytes in 1,234 blocks + +All of which had the same root cause: on an incomplete parse, +we were abandoning the token queue without cleaning up the +allocated data within each queue element. Introduced in +commit 95385fe, when we switched from QList (which recursively +frees contents) to g_queue (which does not). + +We don't yet require glib 2.32 with its g_queue_free_full(), +so open-code it instead. + +CC: qemu-stable@nongnu.org +Signed-off-by: Eric Blake +Message-Id: <1463608012-12760-1-git-send-email-eblake@redhat.com> +Reviewed-by: Markus Armbruster +Signed-off-by: Markus Armbruster +(cherry picked from commit ba4dba54347d5062436a8553f527dbbed6dcf069) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + qobject/json-streamer.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c +index a4db4b8..3c7d6be 100644 +--- a/qobject/json-streamer.c ++++ b/qobject/json-streamer.c +@@ -19,9 +19,15 @@ + #define MAX_TOKEN_COUNT (2ULL << 20) + #define MAX_NESTING (1ULL << 10) + ++static void json_message_free_token(void *token, void *opaque) ++{ ++ g_free(token); ++} ++ + static void json_message_free_tokens(JSONMessageParser *parser) + { + if (parser->tokens) { ++ g_queue_foreach(parser->tokens, json_message_free_token, NULL); + g_queue_free(parser->tokens); + parser->tokens = NULL; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-json-streamer-fix-double-free-on-exiting-during-a-pa.patch b/SOURCES/kvm-json-streamer-fix-double-free-on-exiting-during-a-pa.patch new file mode 100644 index 0000000..602f1a7 --- /dev/null +++ b/SOURCES/kvm-json-streamer-fix-double-free-on-exiting-during-a-pa.patch @@ -0,0 +1,64 @@ +From a781053c1b5084ba32b86229b98b9601c990722c Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:13 +0200 +Subject: [PATCH 15/16] json-streamer: fix double-free on exiting during a + parse + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-17-git-send-email-armbru@redhat.com> +Patchwork-id: 71484 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 15/15] json-streamer: fix double-free on exiting during a parse +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Paolo Bonzini + +Now that json-streamer tries not to leak tokens on incomplete parse, +the tokens can be freed twice if QEMU destroys the json-streamer +object during the parser->emit call. To fix this, create the new +empty GQueue earlier, so that it is already in place when the old +one is passed to parser->emit. + +Reported-by: Changlong Xie +Signed-off-by: Paolo Bonzini +Message-Id: <1467636059-12557-1-git-send-email-pbonzini@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit a942d8fa01f65279cdc135f4294db611bbc088ef) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + qobject/json-streamer.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c +index 3c7d6be..7d041e1 100644 +--- a/qobject/json-streamer.c ++++ b/qobject/json-streamer.c +@@ -38,6 +38,7 @@ static void json_message_process_token(JSONLexer *lexer, GString *input, + { + JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer); + JSONToken *token; ++ GQueue *tokens; + + switch (type) { + case JSON_LCURLY: +@@ -95,9 +96,12 @@ out_emit: + /* send current list of tokens to parser and reset tokenizer */ + parser->brace_count = 0; + parser->bracket_count = 0; +- /* parser->emit takes ownership of parser->tokens. */ +- parser->emit(parser, parser->tokens); ++ /* parser->emit takes ownership of parser->tokens. Remove our own ++ * reference to parser->tokens before handing it out to parser->emit. ++ */ ++ tokens = parser->tokens; + parser->tokens = g_queue_new(); ++ parser->emit(parser, tokens); + parser->token_size = 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-Always-call-close_fn-in-nbd_client_new.patch b/SOURCES/kvm-nbd-Always-call-close_fn-in-nbd_client_new.patch new file mode 100644 index 0000000..60dacb5 --- /dev/null +++ b/SOURCES/kvm-nbd-Always-call-close_fn-in-nbd_client_new.patch @@ -0,0 +1,112 @@ +From 2efca7904a7a71d44bdf715208899e3bb29711df Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Thu, 10 Mar 2016 04:00:51 +0100 +Subject: [PATCH 2/5] nbd: Always call "close_fn" in nbd_client_new + +RH-Author: Fam Zheng +Message-id: <1457582453-13835-2-git-send-email-famz@redhat.com> +Patchwork-id: 69757 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 1/3] nbd: Always call "close_fn" in nbd_client_new +Bugzilla: 1285453 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier + +Rename the parameter "close" to "close_fn" to disambiguous with +close(2). + +This unifies error handling paths of NBDClient allocation: +nbd_client_new will shutdown the socket and call the "close_fn" callback +if negotiation failed, so the caller don't need a different path than +the normal close. + +The returned pointer is never used, make it void in preparation for the +next patch. + +Signed-off-by: Fam Zheng +Message-Id: <1452760863-25350-2-git-send-email-famz@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit ee7d7aabdaea4484e069cb99c9fc54e8cb24b56f) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + include/block/nbd.h + nbd.c + qemu-nbd.c +* nbd_update_server_fd_handler not in downstream; +* Context around the changed line is different. +--- + include/block/nbd.h | 3 +-- + nbd.c | 11 +++++------ + qemu-nbd.c | 4 ++-- + 3 files changed, 8 insertions(+), 10 deletions(-) + +diff --git a/include/block/nbd.h b/include/block/nbd.h +index c90f5e4..92e360e 100644 +--- a/include/block/nbd.h ++++ b/include/block/nbd.h +@@ -92,8 +92,7 @@ NBDExport *nbd_export_find(const char *name); + void nbd_export_set_name(NBDExport *exp, const char *name); + void nbd_export_close_all(void); + +-NBDClient *nbd_client_new(NBDExport *exp, int csock, +- void (*close)(NBDClient *)); ++void nbd_client_new(NBDExport *exp, int csock, void (*close_fn)(NBDClient *)); + void nbd_client_close(NBDClient *client); + void nbd_client_get(NBDClient *client); + void nbd_client_put(NBDClient *client); +diff --git a/nbd.c b/nbd.c +index f258cdd..ba97270 100644 +--- a/nbd.c ++++ b/nbd.c +@@ -1232,8 +1232,7 @@ static void nbd_restart_write(void *opaque) + qemu_coroutine_enter(client->send_coroutine, NULL); + } + +-NBDClient *nbd_client_new(NBDExport *exp, int csock, +- void (*close)(NBDClient *)) ++void nbd_client_new(NBDExport *exp, int csock, void (*close_fn)(NBDClient *)) + { + NBDClient *client; + client = g_malloc0(sizeof(NBDClient)); +@@ -1241,10 +1240,11 @@ NBDClient *nbd_client_new(NBDExport *exp, int csock, + client->exp = exp; + client->sock = csock; + if (nbd_send_negotiate(client) < 0) { +- g_free(client); +- return NULL; ++ shutdown(client->sock, 2); ++ close_fn(client); ++ return; + } +- client->close = close; ++ client->close = close_fn; + qemu_co_mutex_init(&client->send_lock); + qemu_set_fd_handler2(csock, nbd_can_read, nbd_read, NULL, client); + +@@ -1252,5 +1252,4 @@ NBDClient *nbd_client_new(NBDExport *exp, int csock, + QTAILQ_INSERT_TAIL(&exp->clients, client, next); + nbd_export_get(exp); + } +- return client; + } +diff --git a/qemu-nbd.c b/qemu-nbd.c +index ff792ef..047dd49 100644 +--- a/qemu-nbd.c ++++ b/qemu-nbd.c +@@ -297,9 +297,9 @@ static void nbd_accept(void *opaque) + close(fd); + return; + } +- +- if (fd >= 0 && nbd_client_new(exp, fd, nbd_client_closed)) { ++ if (fd >= 0) { + nb_fds++; ++ nbd_client_new(exp, fd, nbd_client_closed); + } + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-client_close-on-error-in-nbd_co_client_start.patch b/SOURCES/kvm-nbd-client_close-on-error-in-nbd_co_client_start.patch new file mode 100644 index 0000000..9479ecd --- /dev/null +++ b/SOURCES/kvm-nbd-client_close-on-error-in-nbd_co_client_start.patch @@ -0,0 +1,50 @@ +From c62e0877b191e5fba9b678bbd518a57c8fdf7099 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Thu, 10 Mar 2016 04:00:53 +0100 +Subject: [PATCH 4/5] nbd: client_close on error in nbd_co_client_start + +RH-Author: Fam Zheng +Message-id: <1457582453-13835-4-git-send-email-famz@redhat.com> +Patchwork-id: 69759 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 3/3] nbd: client_close on error in nbd_co_client_start +Bugzilla: 1285453 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier + +From: Max Reitz + +Use client_close() if an error in nbd_co_client_start() occurs instead +of manually inlining parts of it. This fixes an assertion error on the +server side if nbd_negotiate() fails. + +Signed-off-by: Max Reitz +Acked-by: Paolo Bonzini +Reviewed-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit d3780c2dce2c452759ee9d94f9d824cf14cc3ab8) +Signed-off-by: Fam Zheng + +Downstream: client_close -> nbd_client_close. +Signed-off-by: Miroslav Rezanina +--- + nbd.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/nbd.c b/nbd.c +index 97aeecb..c20e57e 100644 +--- a/nbd.c ++++ b/nbd.c +@@ -1282,8 +1282,7 @@ static coroutine_fn void nbd_co_client_start(void *opaque) + nbd_export_get(exp); + } + if (nbd_negotiate(data)) { +- shutdown(client->sock, 2); +- client->close(client); ++ nbd_client_close(client); + goto out; + } + qemu_co_mutex_init(&client->send_lock); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Coroutine-based-negotiation.patch b/SOURCES/kvm-nbd-server-Coroutine-based-negotiation.patch new file mode 100644 index 0000000..9083ba7 --- /dev/null +++ b/SOURCES/kvm-nbd-server-Coroutine-based-negotiation.patch @@ -0,0 +1,262 @@ +From 2a68d801c63137c3d1fe9fa96f0193eb2d1576f5 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Thu, 10 Mar 2016 04:00:52 +0100 +Subject: [PATCH 3/5] nbd-server: Coroutine based negotiation + +RH-Author: Fam Zheng +Message-id: <1457582453-13835-3-git-send-email-famz@redhat.com> +Patchwork-id: 69758 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 2/3] nbd-server: Coroutine based negotiation +Bugzilla: 1285453 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Laurent Vivier + +Create a coroutine in nbd_client_new, so that nbd_send_negotiate doesn't +need qemu_set_block(). + +Handlers need to be set temporarily for csock fd in case the coroutine +yields during I/O. + +With this, if the other end disappears in the middle of the negotiation, +we don't block the whole event loop. + +To make the code clearer, unify all function names that belong to +negotiate, so they are less likely to be misused. This is important +because we rely on negotiation staying in main loop, as commented in +nbd_negotiate_read/write(). + +Signed-off-by: Fam Zheng +Message-Id: <1452760863-25350-4-git-send-email-famz@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 1a6245a5b0b4e8d822c739b403fc67c8a7bc8d12) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina + +Conflicts: + nbd.c +Downstream doesn't have new style protocol, and the code is not split. +The patch is redone. +--- + nbd.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 82 insertions(+), 24 deletions(-) + +diff --git a/nbd.c b/nbd.c +index ba97270..97aeecb 100644 +--- a/nbd.c ++++ b/nbd.c +@@ -167,6 +167,41 @@ ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read) + return offset; + } + ++static void nbd_negotiate_continue(void *opaque) ++{ ++ qemu_coroutine_enter(opaque, NULL); ++} ++ ++static ssize_t read_sync(int fd, void *buffer, size_t size); ++static ssize_t write_sync(int fd, void *buffer, size_t size); ++ ++static ssize_t nbd_negotiate_read(int fd, void *buffer, size_t size) ++{ ++ ssize_t ret; ++ ++ assert(qemu_in_coroutine()); ++ /* Negotiation are always in main loop. */ ++ qemu_set_fd_handler(fd, nbd_negotiate_continue, NULL, ++ qemu_coroutine_self()); ++ ret = read_sync(fd, buffer, size); ++ qemu_set_fd_handler(fd, NULL, NULL, NULL); ++ return ret; ++ ++} ++ ++static ssize_t nbd_negotiate_write(int fd, void *buffer, size_t size) ++{ ++ ssize_t ret; ++ ++ assert(qemu_in_coroutine()); ++ /* Negotiation are always in main loop. */ ++ qemu_set_fd_handler(fd, NULL, nbd_negotiate_continue, ++ qemu_coroutine_self()); ++ ret = write_sync(fd, buffer, size); ++ qemu_set_fd_handler(fd, NULL, NULL, NULL); ++ return ret; ++} ++ + static ssize_t read_sync(int fd, void *buffer, size_t size) + { + /* Sockets are kept in blocking mode in the negotiation phase. After +@@ -280,7 +315,7 @@ int unix_socket_outgoing(const char *path) + + */ + +-static int nbd_receive_options(NBDClient *client) ++static coroutine_fn int nbd_negotiate_receive_options(NBDClient *client) + { + int csock = client->sock; + char name[256]; +@@ -297,7 +332,7 @@ static int nbd_receive_options(NBDClient *client) + */ + + rc = -EINVAL; +- if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { ++ if (nbd_negotiate_read(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { + LOG("read failed"); + goto fail; + } +@@ -307,7 +342,7 @@ static int nbd_receive_options(NBDClient *client) + goto fail; + } + +- if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) { ++ if (nbd_negotiate_read(csock, &magic, sizeof(magic)) != sizeof(magic)) { + LOG("read failed"); + goto fail; + } +@@ -317,7 +352,7 @@ static int nbd_receive_options(NBDClient *client) + goto fail; + } + +- if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { ++ if (nbd_negotiate_read(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) { + LOG("read failed"); + goto fail; + } +@@ -327,7 +362,7 @@ static int nbd_receive_options(NBDClient *client) + goto fail; + } + +- if (read_sync(csock, &length, sizeof(length)) != sizeof(length)) { ++ if (nbd_negotiate_read(csock, &length, sizeof(length)) != sizeof(length)) { + LOG("read failed"); + goto fail; + } +@@ -337,7 +372,7 @@ static int nbd_receive_options(NBDClient *client) + LOG("Bad length received"); + goto fail; + } +- if (read_sync(csock, name, length) != length) { ++ if (nbd_negotiate_read(csock, name, length) != length) { + LOG("read failed"); + goto fail; + } +@@ -358,8 +393,14 @@ fail: + return rc; + } + +-static int nbd_send_negotiate(NBDClient *client) ++typedef struct { ++ NBDClient *client; ++ Coroutine *co; ++} NBDClientNewData; ++ ++static coroutine_fn int nbd_negotiate(NBDClientNewData *data) + { ++ NBDClient *client = data->client; + int csock = client->sock; + char buf[8 + 8 + 8 + 128]; + int rc; +@@ -385,7 +426,6 @@ static int nbd_send_negotiate(NBDClient *client) + [28 .. 151] reserved (0) + */ + +- qemu_set_block(csock); + rc = -EINVAL; + + TRACE("Beginning negotiation."); +@@ -401,16 +441,16 @@ static int nbd_send_negotiate(NBDClient *client) + } + + if (client->exp) { +- if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { ++ if (nbd_negotiate_write(csock, buf, sizeof(buf)) != sizeof(buf)) { + LOG("write failed"); + goto fail; + } + } else { +- if (write_sync(csock, buf, 18) != 18) { ++ if (nbd_negotiate_write(csock, buf, 18) != 18) { + LOG("write failed"); + goto fail; + } +- rc = nbd_receive_options(client); ++ rc = nbd_negotiate_receive_options(client); + if (rc < 0) { + LOG("option negotiation failed"); + goto fail; +@@ -419,7 +459,8 @@ static int nbd_send_negotiate(NBDClient *client) + assert ((client->exp->nbdflags & ~65535) == 0); + cpu_to_be64w((uint64_t*)(buf + 18), client->exp->size); + cpu_to_be16w((uint16_t*)(buf + 26), client->exp->nbdflags | myflags); +- if (write_sync(csock, buf + 18, sizeof(buf) - 18) != sizeof(buf) - 18) { ++ if (nbd_negotiate_write(csock, buf + 18, ++ sizeof(buf) - 18) != sizeof(buf) - 18) { + LOG("write failed"); + goto fail; + } +@@ -428,7 +469,6 @@ static int nbd_send_negotiate(NBDClient *client) + TRACE("Negotiation succeeded."); + rc = 0; + fail: +- qemu_set_nonblock(csock); + return rc; + } + +@@ -1232,24 +1272,42 @@ static void nbd_restart_write(void *opaque) + qemu_coroutine_enter(client->send_coroutine, NULL); + } + ++static coroutine_fn void nbd_co_client_start(void *opaque) ++{ ++ NBDClientNewData *data = opaque; ++ NBDClient *client = data->client; ++ NBDExport *exp = client->exp; ++ ++ if (exp) { ++ nbd_export_get(exp); ++ } ++ if (nbd_negotiate(data)) { ++ shutdown(client->sock, 2); ++ client->close(client); ++ goto out; ++ } ++ qemu_co_mutex_init(&client->send_lock); ++ qemu_set_fd_handler2(client->sock, nbd_can_read, nbd_read, NULL, client); ++ ++ if (exp) { ++ QTAILQ_INSERT_TAIL(&exp->clients, client, next); ++ } ++out: ++ g_free(data); ++} ++ + void nbd_client_new(NBDExport *exp, int csock, void (*close_fn)(NBDClient *)) + { + NBDClient *client; ++ NBDClientNewData *data = g_new(NBDClientNewData, 1); ++ + client = g_malloc0(sizeof(NBDClient)); + client->refcount = 1; + client->exp = exp; + client->sock = csock; +- if (nbd_send_negotiate(client) < 0) { +- shutdown(client->sock, 2); +- close_fn(client); +- return; +- } + client->close = close_fn; +- qemu_co_mutex_init(&client->send_lock); +- qemu_set_fd_handler2(csock, nbd_can_read, nbd_read, NULL, client); + +- if (exp) { +- QTAILQ_INSERT_TAIL(&exp->clients, client, next); +- nbd_export_get(exp); +- } ++ data->client = client; ++ data->co = qemu_coroutine_create(nbd_co_client_start); ++ qemu_coroutine_enter(data->co, data); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-nbd-server-Set-O_NONBLOCK-on-client-fd.patch b/SOURCES/kvm-nbd-server-Set-O_NONBLOCK-on-client-fd.patch new file mode 100644 index 0000000..6b9b473 --- /dev/null +++ b/SOURCES/kvm-nbd-server-Set-O_NONBLOCK-on-client-fd.patch @@ -0,0 +1,44 @@ +From e36a5a8613df42339773ebf48e07d063ad7484e8 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 5 Sep 2016 01:18:15 +0200 +Subject: [PATCH] nbd-server: Set O_NONBLOCK on client fd + +RH-Author: Fam Zheng +Message-id: <1473038295-7193-1-git-send-email-famz@redhat.com> +Patchwork-id: 72141 +O-Subject: [RHEL-7.3 qemu-kvm PATCH] nbd-server: Set O_NONBLOCK on client fd +Bugzilla: 1285453 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Max Reitz + +Upstream: upstream uses IO channels that is not present in downstream. +Backporting that deserves a separate and deliberate justification BZ, +for 7.4. + +Even with 2a68d80 (nbd-server: Coroutine based negotiation), QEMU still +hangs when client hangs, because recvmsg the socket fd is blocking. Set +the O_NONBLOCK to fix this. + +Analyzed-by: Stefan Hajnoczi +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + nbd.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/nbd.c b/nbd.c +index c20e57e..8a32e18 100644 +--- a/nbd.c ++++ b/nbd.c +@@ -1281,6 +1281,7 @@ static coroutine_fn void nbd_co_client_start(void *opaque) + if (exp) { + nbd_export_get(exp); + } ++ qemu_set_nonblock(client->sock); + if (nbd_negotiate(data)) { + nbd_client_close(client); + goto out; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-net-Make-qmp_query_rx_filter-with-name-argument-more.patch b/SOURCES/kvm-net-Make-qmp_query_rx_filter-with-name-argument-more.patch new file mode 100644 index 0000000..28e945b --- /dev/null +++ b/SOURCES/kvm-net-Make-qmp_query_rx_filter-with-name-argument-more.patch @@ -0,0 +1,47 @@ +From 9c2a6798c053cec989e02935e810a0d239fb493c Mon Sep 17 00:00:00 2001 +From: Vlad Yasevich +Date: Wed, 16 Dec 2015 02:59:35 +0100 +Subject: [PATCH 1/2] net: Make qmp_query_rx_filter() with name argument more + obvious + +RH-Author: Vlad Yasevich +Message-id: <1450234776-7779-2-git-send-email-vyasevic@redhat.com> +Patchwork-id: 68620 +O-Subject: [RHEL7.3 qemu-kvm PATCH 1/2] net: Make qmp_query_rx_filter() with name argument more obvious +Bugzilla: 1269738 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Michael S. Tsirkin + +From: Markus Armbruster + +With a client name, the QMP command is specified to return a list of +one element. This isn't locally obvious in the code. Make it so. + +Signed-off-by: Markus Armbruster +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 638fb14169ad96cf9bc0dd5f61460daaecee5bb1) +Signed-off-by: Vladislav Yasevich +Signed-off-by: Miroslav Rezanina +--- + net/net.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/net.c b/net/net.c +index a8c49fc..0be50a0 100644 +--- a/net/net.c ++++ b/net/net.c +@@ -1000,6 +1000,10 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, + " rx-filter querying", name); + break; + } ++ ++ if (has_name) { ++ break; ++ } + } + + if (filter_list == NULL && !error_is_set(errp) && has_name) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-pc-set-the-OEM-fields-in-the-RSDT-and-the-FADT-from-.patch b/SOURCES/kvm-pc-set-the-OEM-fields-in-the-RSDT-and-the-FADT-from-.patch new file mode 100644 index 0000000..f1d5ebf --- /dev/null +++ b/SOURCES/kvm-pc-set-the-OEM-fields-in-the-RSDT-and-the-FADT-from-.patch @@ -0,0 +1,133 @@ +From 607904cf94b1dee91c74522aedebda308ffba93d Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Wed, 11 May 2016 12:33:48 +0200 +Subject: [PATCH 09/10] pc: set the OEM fields in the RSDT and the FADT from + the SLIC + +RH-Author: Laszlo Ersek +Message-id: <1462970028-10959-8-git-send-email-lersek@redhat.com> +Patchwork-id: 70384 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 7/7] pc: set the OEM fields in the RSDT and the FADT from the SLIC +Bugzilla: 1330969 +RH-Acked-by: Igor Mammedov +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Thomas Huth + +The Microsoft spec about the SLIC and MSDM ACPI tables at + requires the OEM ID and +OEM Table ID fields to be consistent between the SLIC and the RSDT/XSDT. +That further affects the FADT, because a similar match between the FADT +and the RSDT/XSDT is required by the ACPI spec in general. + +This patch wires up the previous three patches. + +Cc: "Michael S. Tsirkin" (supporter:ACPI/SMBIOS) +Cc: Igor Mammedov (supporter:ACPI/SMBIOS) +Cc: Paolo Bonzini (maintainer:X86) +Cc: Richard W.M. Jones +Cc: Aleksei Kovura +Cc: Michael Tokarev +Cc: Steven Newbury +RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1248758 +LP: https://bugs.launchpad.net/qemu/+bug/1533848 +Signed-off-by: Laszlo Ersek +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Steven Newbury +(cherry picked from commit ae12374951f07157f7a52c8d848b90f8eec722fb) +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/i386/acpi-build.c + +RHEL-7 backport note: conflict due to downstream lacking 7c2c1fa5f428 +("pc: acpi: use local var for accessing ACPI tables blob in +acpi_build()"). + +Signed-off-by: Laszlo Ersek +--- + hw/i386/acpi-build.c | 13 +++++++++---- + qemu-options.hx | 4 ++++ + 2 files changed, 13 insertions(+), 4 deletions(-) +--- + hw/i386/acpi-build.c | 13 +++++++++---- + qemu-options.hx | 4 ++++ + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index d9433e6..85291f5 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -511,7 +511,8 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm) + /* FADT */ + static void + build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, +- unsigned facs, unsigned dsdt) ++ unsigned facs, unsigned dsdt, ++ const char *oem_id, const char *oem_table_id) + { + AcpiFadtDescriptorRev1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); + +@@ -532,7 +533,7 @@ build_fadt(GArray *table_data, GArray *linker, AcpiPmInfo *pm, + fadt_setup(fadt, pm); + + build_header(linker, table_data, +- (void *)fadt, "FACP", sizeof(*fadt), 1, NULL, NULL); ++ (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id); + } + + static void +@@ -1065,6 +1066,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) + AcpiMcfgInfo mcfg; + PcPciInfo pci; + uint8_t *u; ++ AcpiSlicOem slic_oem = { .id = NULL, .table_id = NULL }; + + acpi_get_cpu_info(&cpu); + acpi_get_pm_info(&pm); +@@ -1072,6 +1074,7 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) + acpi_get_hotplug_info(&misc); + acpi_get_misc_info(&misc); + acpi_get_pci_info(&pci); ++ acpi_get_slic_oem(&slic_oem); + + table_offsets = g_array_new(false, true /* clear */, + sizeof(uint32_t)); +@@ -1095,7 +1098,8 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) + + /* ACPI tables pointed to by RSDT */ + acpi_add_table(table_offsets, tables->table_data); +- build_fadt(tables->table_data, tables->linker, &pm, facs, dsdt); ++ build_fadt(tables->table_data, tables->linker, &pm, facs, dsdt, ++ slic_oem.id, slic_oem.table_id); + + acpi_add_table(table_offsets, tables->table_data); + build_ssdt(tables->table_data, tables->linker, &cpu, &pm, &misc, &pci, +@@ -1127,7 +1131,8 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) + + /* RSDT is pointed to by RSDP */ + rsdt = tables->table_data->len; +- build_rsdt(tables->table_data, tables->linker, table_offsets, NULL, NULL); ++ build_rsdt(tables->table_data, tables->linker, table_offsets, ++ slic_oem.id, slic_oem.table_id); + + /* RSDP is in FSEG memory, so allocate it separately */ + build_rsdp(tables->rsdp, tables->linker, rsdt); +diff --git a/qemu-options.hx b/qemu-options.hx +index 62c3e06..24ffab6 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -1295,6 +1295,10 @@ ACPI headers (possible overridden by other options). + For data=, only data + portion of the table is used, all header information is specified in the + command line. ++If a SLIC table is supplied to QEMU, then the SLIC's oem_id and oem_table_id ++fields will override the same in the RSDT and the FADT (a.k.a. FACP), in order ++to ensure the field matches required by the Microsoft SLIC spec and the ACPI ++spec. + ETEXI + + DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Check-for-trailing-chars.patch b/SOURCES/kvm-qemu-io-Check-for-trailing-chars.patch new file mode 100644 index 0000000..d4d0f7f --- /dev/null +++ b/SOURCES/kvm-qemu-io-Check-for-trailing-chars.patch @@ -0,0 +1,59 @@ +From 362faad8e8f4c2c2c875df12f6bbae7964c0146d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:38 +0100 +Subject: [PATCH 19/27] qemu-io: Check for trailing chars + +RH-Author: John Snow +Message-id: <1448300320-7772-20-git-send-email-jsnow@redhat.com> +Patchwork-id: 68449 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 19/21] qemu-io: Check for trailing chars +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +Make sure there's not trailing garbage, e.g. +"64k-whatever-i-want-here" + +Reported-by: Max Reitz +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit ef5a788527b2038d742b057a415ab4d0e735e98f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina + +Conflicts: + qemu-io-cmds.c: + - Downstream still uses strtosz_suffix, not + qemu_strtosz_suffix. + +Signed-off-by: John Snow +--- + qemu-io-cmds.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index 95345fe..6ea027d 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -124,7 +124,14 @@ static char **breakline(char *input, int *count) + static int64_t cvtnum(const char *s) + { + char *end; +- return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B); ++ int64_t ret; ++ ++ ret = strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B); ++ if (*end != '\0') { ++ /* Detritus at the end of the string */ ++ return -EINVAL; ++ } ++ return ret; + } + + #define EXABYTES(x) ((long long)(x) << 60) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Correct-error-messages.patch b/SOURCES/kvm-qemu-io-Correct-error-messages.patch new file mode 100644 index 0000000..07f3345 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Correct-error-messages.patch @@ -0,0 +1,218 @@ +From 8adbd2914ccd44e0b1766690b514bda213b88740 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:39 +0100 +Subject: [PATCH 20/27] qemu-io: Correct error messages + +RH-Author: John Snow +Message-id: <1448300320-7772-21-git-send-email-jsnow@redhat.com> +Patchwork-id: 68446 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 20/21] qemu-io: Correct error messages +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +Reported-by: Max Reitz +Signed-off-by: John Snow +Reviewed-by: Eric Blake +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit a9ecfa004f2dd83df612daac4a87dfc3a0feba28) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina + +Conflicts: + qemu-io-cmds.c: + - Fixes to sigraise are not backported. + +Signed-off-by: John Snow +--- + qemu-io-cmds.c | 51 +++++++++++++++++++++++++++++++++------------------ + 1 file changed, 33 insertions(+), 18 deletions(-) + +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index 6ea027d..b41d6ee 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -134,6 +134,21 @@ static int64_t cvtnum(const char *s) + return ret; + } + ++static void print_cvtnum_err(int64_t rc, const char *arg) ++{ ++ switch (rc) { ++ case -EINVAL: ++ printf("Parsing error: non-numeric argument," ++ " or extraneous/unrecognized suffix -- %s\n", arg); ++ break; ++ case -ERANGE: ++ printf("Parsing error: argument too large -- %s\n", arg); ++ break; ++ default: ++ printf("Parsing error: %s\n", arg); ++ } ++} ++ + #define EXABYTES(x) ((long long)(x) << 60) + #define PETABYTES(x) ((long long)(x) << 50) + #define TERABYTES(x) ((long long)(x) << 40) +@@ -355,13 +370,13 @@ create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov, + + len = cvtnum(arg); + if (len < 0) { +- printf("non-numeric length argument -- %s\n", arg); ++ print_cvtnum_err(len, arg); + goto fail; + } + + /* should be SIZE_T_MAX, but that doesn't exist */ + if (len > INT_MAX) { +- printf("too large length argument -- %s\n", arg); ++ printf("Argument '%s' exceeds maximum size %d\n", arg, INT_MAX); + goto fail; + } + +@@ -688,7 +703,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) + lflag = 1; + pattern_count = cvtnum(optarg); + if (pattern_count < 0) { +- printf("non-numeric length argument -- %s\n", optarg); ++ print_cvtnum_err(pattern_count, optarg); + return 0; + } + break; +@@ -709,7 +724,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) + sflag = 1; + pattern_offset = cvtnum(optarg); + if (pattern_offset < 0) { +- printf("non-numeric length argument -- %s\n", optarg); ++ print_cvtnum_err(pattern_offset, optarg); + return 0; + } + break; +@@ -732,14 +747,14 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) + + offset = cvtnum(argv[optind]); + if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(offset, argv[optind]); + return 0; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(count, argv[optind]); + return 0; + } else if (count > SIZE_MAX) { + printf("length cannot exceed %" PRIu64 ", given %s\n", +@@ -894,7 +909,7 @@ static int readv_f(BlockDriverState *bs, int argc, char **argv) + + offset = cvtnum(argv[optind]); + if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(offset, argv[optind]); + return 0; + } + optind++; +@@ -1043,14 +1058,14 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) + + offset = cvtnum(argv[optind]); + if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(offset, argv[optind]); + return 0; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(count, argv[optind]); + return 0; + } else if (count > SIZE_MAX) { + printf("length cannot exceed %" PRIu64 ", given %s\n", +@@ -1179,7 +1194,7 @@ static int writev_f(BlockDriverState *bs, int argc, char **argv) + + offset = cvtnum(argv[optind]); + if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(offset, argv[optind]); + return 0; + } + optind++; +@@ -1306,7 +1321,7 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) + /* Read the offset of the request */ + offset = cvtnum(argv[optind]); + if (offset < 0) { +- printf("non-numeric offset argument -- %s\n", argv[optind]); ++ print_cvtnum_err(offset, argv[optind]); + goto out; + } + optind++; +@@ -1526,7 +1541,7 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv) + + ctx->offset = cvtnum(argv[optind]); + if (ctx->offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(ctx->offset, argv[optind]); + g_free(ctx); + return 0; + } +@@ -1618,7 +1633,7 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv) + + ctx->offset = cvtnum(argv[optind]); + if (ctx->offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(ctx->offset, argv[optind]); + g_free(ctx); + return 0; + } +@@ -1676,7 +1691,7 @@ static int truncate_f(BlockDriverState *bs, int argc, char **argv) + + offset = cvtnum(argv[1]); + if (offset < 0) { +- printf("non-numeric truncate argument -- %s\n", argv[1]); ++ print_cvtnum_err(offset, argv[1]); + return 0; + } + +@@ -1822,14 +1837,14 @@ static int discard_f(BlockDriverState *bs, int argc, char **argv) + + offset = cvtnum(argv[optind]); + if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(offset, argv[optind]); + return 0; + } + + optind++; + count = cvtnum(argv[optind]); + if (count < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); ++ print_cvtnum_err(count, argv[optind]); + return 0; + } else if (count >> BDRV_SECTOR_BITS > INT_MAX) { + printf("length cannot exceed %"PRIu64", given %s\n", +@@ -1867,7 +1882,7 @@ static int alloc_f(BlockDriverState *bs, int argc, char **argv) + + offset = cvtnum(argv[1]); + if (offset < 0) { +- printf("non-numeric offset argument -- %s\n", argv[1]); ++ print_cvtnum_err(offset, argv[1]); + return 0; + } else if (offset & 0x1ff) { + printf("offset %" PRId64 " is not sector aligned\n", +@@ -1878,7 +1893,7 @@ static int alloc_f(BlockDriverState *bs, int argc, char **argv) + if (argc == 3) { + nb_sectors = cvtnum(argv[2]); + if (nb_sectors < 0) { +- printf("non-numeric length argument -- %s\n", argv[2]); ++ print_cvtnum_err(nb_sectors, argv[2]); + return 0; + } else if (nb_sectors > INT_MAX) { + printf("length argument cannot exceed %d, given %s\n", +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Don-t-use-global-bs-in-command-implementatio.patch b/SOURCES/kvm-qemu-io-Don-t-use-global-bs-in-command-implementatio.patch new file mode 100644 index 0000000..7a8bd97 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Don-t-use-global-bs-in-command-implementatio.patch @@ -0,0 +1,737 @@ +From 2653e21a25d8fb99479337c785e81b07f755acda Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:24 +0100 +Subject: [PATCH 05/27] qemu-io: Don't use global bs in command implementations + +RH-Author: John Snow +Message-id: <1448300320-7772-6-git-send-email-jsnow@redhat.com> +Patchwork-id: 68433 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 05/21] qemu-io: Don't use global bs in command implementations +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Pass in the BlockDriverState to the command handlers instead of using +the global variable. This is an important step to make the commands +usable outside of qemu-io. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 734c3b85cb72d264ad2b38a87f30304e05de2cb1) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina + +Conflicts: + qemu-io.c + Number of arguments to bdrv_co_write_zeroes + bdrv_unref used downstream instead of bdrv_delete + downstream, local_err used for bdrv_open + downstream, error_abort used for bdrv_new + map_is_allocated was never backported from a00e81e98f71 + sleep_f was backported, adjust its signature + +Signed-off-by: John Snow +--- + cmd.c | 6 ++- + cmd.h | 8 ++- + qemu-io.c | 164 ++++++++++++++++++++++++++++++++++---------------------------- + 3 files changed, 99 insertions(+), 79 deletions(-) + +diff --git a/cmd.c b/cmd.c +index 214c6f7..d501aab 100644 +--- a/cmd.c ++++ b/cmd.c +@@ -57,7 +57,7 @@ check_command( + const cmdinfo_t *ci) + { + if (check_func) +- return check_func(ci); ++ return check_func(qemuio_bs, ci); + return 1; + } + +@@ -103,7 +103,7 @@ command( + return 0; + } + optind = 0; +- return ct->cfunc(argc, argv); ++ return ct->cfunc(qemuio_bs, argc, argv); + } + + const cmdinfo_t * +@@ -452,6 +452,7 @@ static cmdinfo_t quit_cmd; + /* ARGSUSED */ + static int + quit_f( ++ BlockDriverState *bs, + int argc, + char **argv) + { +@@ -490,6 +491,7 @@ help_all(void) + + static int + help_f( ++ BlockDriverState *bs, + int argc, + char **argv) + { +diff --git a/cmd.h b/cmd.h +index 4dcfe88..ccf6336 100644 +--- a/cmd.h ++++ b/cmd.h +@@ -17,9 +17,13 @@ + #ifndef __COMMAND_H__ + #define __COMMAND_H__ + ++#include "qemu-common.h" ++ + #define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ + +-typedef int (*cfunc_t)(int argc, char **argv); ++extern BlockDriverState *qemuio_bs; ++ ++typedef int (*cfunc_t)(BlockDriverState *bs, int argc, char **argv); + typedef void (*helpfunc_t)(void); + + typedef struct cmdinfo { +@@ -41,7 +45,7 @@ extern int ncmds; + void help_init(void); + void quit_init(void); + +-typedef int (*checkfunc_t)(const cmdinfo_t *ci); ++typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci); + + void add_command(const cmdinfo_t *ci); + void add_user_command(char *optarg); +diff --git a/qemu-io.c b/qemu-io.c +index e4fa2fc..c3cc4f3 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -29,8 +29,8 @@ + #define CMD_NOFILE_OK 0x01 + + char *progname; +-static BlockDriverState *bs; + ++BlockDriverState *qemuio_bs; + static int misalign; + + static int64_t cvtnum(const char *s) +@@ -67,7 +67,7 @@ static int parse_pattern(const char *arg) + */ + + #define MISALIGN_OFFSET 16 +-static void *qemu_io_alloc(size_t len, int pattern) ++static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern) + { + void *buf; + +@@ -140,7 +140,8 @@ static void print_report(const char *op, struct timeval *t, int64_t offset, + * vector matching it. + */ + static void * +-create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern) ++create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov, ++ int pattern) + { + size_t *sizes = g_new0(size_t, nr_iov); + size_t count = 0; +@@ -176,7 +177,7 @@ create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern) + + qemu_iovec_init(qiov, nr_iov); + +- buf = p = qemu_io_alloc(count, pattern); ++ buf = p = qemu_io_alloc(bs, count, pattern); + + for (i = 0; i < nr_iov; i++) { + qemu_iovec_add(qiov, p, sizes[i]); +@@ -188,7 +189,8 @@ fail: + return buf; + } + +-static int do_read(char *buf, int64_t offset, int count, int *total) ++static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count, ++ int *total) + { + int ret; + +@@ -200,7 +202,8 @@ static int do_read(char *buf, int64_t offset, int count, int *total) + return 1; + } + +-static int do_write(char *buf, int64_t offset, int count, int *total) ++static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count, ++ int *total) + { + int ret; + +@@ -212,7 +215,8 @@ static int do_write(char *buf, int64_t offset, int count, int *total) + return 1; + } + +-static int do_pread(char *buf, int64_t offset, int count, int *total) ++static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count, ++ int *total) + { + *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); + if (*total < 0) { +@@ -221,7 +225,8 @@ static int do_pread(char *buf, int64_t offset, int count, int *total) + return 1; + } + +-static int do_pwrite(char *buf, int64_t offset, int count, int *total) ++static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count, ++ int *total) + { + *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); + if (*total < 0) { +@@ -231,6 +236,7 @@ static int do_pwrite(char *buf, int64_t offset, int count, int *total) + } + + typedef struct { ++ BlockDriverState *bs; + int64_t offset; + int count; + int *total; +@@ -242,7 +248,7 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque) + { + CoWriteZeroes *data = opaque; + +- data->ret = bdrv_co_write_zeroes(bs, data->offset / BDRV_SECTOR_SIZE, ++ data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE, + data->count / BDRV_SECTOR_SIZE, 0); + data->done = true; + if (data->ret < 0) { +@@ -253,10 +259,12 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque) + *data->total = data->count; + } + +-static int do_co_write_zeroes(int64_t offset, int count, int *total) ++static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, ++ int *total) + { + Coroutine *co; + CoWriteZeroes data = { ++ .bs = bs, + .offset = offset, + .count = count, + .total = total, +@@ -275,7 +283,8 @@ static int do_co_write_zeroes(int64_t offset, int count, int *total) + } + } + +-static int do_write_compressed(char *buf, int64_t offset, int count, int *total) ++static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset, ++ int count, int *total) + { + int ret; + +@@ -287,7 +296,8 @@ static int do_write_compressed(char *buf, int64_t offset, int count, int *total) + return 1; + } + +-static int do_load_vmstate(char *buf, int64_t offset, int count, int *total) ++static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset, ++ int count, int *total) + { + *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); + if (*total < 0) { +@@ -296,7 +306,8 @@ static int do_load_vmstate(char *buf, int64_t offset, int count, int *total) + return 1; + } + +-static int do_save_vmstate(char *buf, int64_t offset, int count, int *total) ++static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset, ++ int count, int *total) + { + *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); + if (*total < 0) { +@@ -311,7 +322,8 @@ static void aio_rw_done(void *opaque, int ret) + *(int *)opaque = ret; + } + +-static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total) ++static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov, ++ int64_t offset, int *total) + { + int async_ret = NOT_DONE; + +@@ -325,7 +337,8 @@ static int do_aio_readv(QEMUIOVector *qiov, int64_t offset, int *total) + return async_ret < 0 ? async_ret : 1; + } + +-static int do_aio_writev(QEMUIOVector *qiov, int64_t offset, int *total) ++static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov, ++ int64_t offset, int *total) + { + int async_ret = NOT_DONE; + +@@ -354,7 +367,8 @@ static void multiwrite_cb(void *opaque, int ret) + } + } + +-static int do_aio_multiwrite(BlockRequest* reqs, int num_reqs, int *total) ++static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs, ++ int num_reqs, int *total) + { + int i, ret; + struct multiwrite_async_ret async_ret = { +@@ -403,7 +417,7 @@ static void read_help(void) + "\n"); + } + +-static int read_f(int argc, char **argv); ++static int read_f(BlockDriverState *bs, int argc, char **argv); + + static const cmdinfo_t read_cmd = { + .name = "read", +@@ -416,7 +430,7 @@ static const cmdinfo_t read_cmd = { + .help = read_help, + }; + +-static int read_f(int argc, char **argv) ++static int read_f(BlockDriverState *bs, int argc, char **argv) + { + struct timeval t1, t2; + int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; +@@ -522,15 +536,15 @@ static int read_f(int argc, char **argv) + } + } + +- buf = qemu_io_alloc(count, 0xab); ++ buf = qemu_io_alloc(bs, count, 0xab); + + gettimeofday(&t1, NULL); + if (pflag) { +- cnt = do_pread(buf, offset, count, &total); ++ cnt = do_pread(bs, buf, offset, count, &total); + } else if (bflag) { +- cnt = do_load_vmstate(buf, offset, count, &total); ++ cnt = do_load_vmstate(bs, buf, offset, count, &total); + } else { +- cnt = do_read(buf, offset, count, &total); ++ cnt = do_read(bs, buf, offset, count, &total); + } + gettimeofday(&t2, NULL); + +@@ -587,7 +601,7 @@ static void readv_help(void) + "\n"); + } + +-static int readv_f(int argc, char **argv); ++static int readv_f(BlockDriverState *bs, int argc, char **argv); + + static const cmdinfo_t readv_cmd = { + .name = "readv", +@@ -599,7 +613,7 @@ static const cmdinfo_t readv_cmd = { + .help = readv_help, + }; + +-static int readv_f(int argc, char **argv) ++static int readv_f(BlockDriverState *bs, int argc, char **argv) + { + struct timeval t1, t2; + int Cflag = 0, qflag = 0, vflag = 0; +@@ -655,13 +669,13 @@ static int readv_f(int argc, char **argv) + } + + nr_iov = argc - optind; +- buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab); ++ buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab); + if (buf == NULL) { + return 0; + } + + gettimeofday(&t1, NULL); +- cnt = do_aio_readv(&qiov, offset, &total); ++ cnt = do_aio_readv(bs, &qiov, offset, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { +@@ -718,7 +732,7 @@ static void write_help(void) + "\n"); + } + +-static int write_f(int argc, char **argv); ++static int write_f(BlockDriverState *bs, int argc, char **argv); + + static const cmdinfo_t write_cmd = { + .name = "write", +@@ -731,7 +745,7 @@ static const cmdinfo_t write_cmd = { + .help = write_help, + }; + +-static int write_f(int argc, char **argv) ++static int write_f(BlockDriverState *bs, int argc, char **argv) + { + struct timeval t1, t2; + int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0; +@@ -818,20 +832,20 @@ static int write_f(int argc, char **argv) + } + + if (!zflag) { +- buf = qemu_io_alloc(count, pattern); ++ buf = qemu_io_alloc(bs, count, pattern); + } + + gettimeofday(&t1, NULL); + if (pflag) { +- cnt = do_pwrite(buf, offset, count, &total); ++ cnt = do_pwrite(bs, buf, offset, count, &total); + } else if (bflag) { +- cnt = do_save_vmstate(buf, offset, count, &total); ++ cnt = do_save_vmstate(bs, buf, offset, count, &total); + } else if (zflag) { +- cnt = do_co_write_zeroes(offset, count, &total); ++ cnt = do_co_write_zeroes(bs, offset, count, &total); + } else if (cflag) { +- cnt = do_write_compressed(buf, offset, count, &total); ++ cnt = do_write_compressed(bs, buf, offset, count, &total); + } else { +- cnt = do_write(buf, offset, count, &total); ++ cnt = do_write(bs, buf, offset, count, &total); + } + gettimeofday(&t2, NULL); + +@@ -874,7 +888,7 @@ writev_help(void) + "\n"); + } + +-static int writev_f(int argc, char **argv); ++static int writev_f(BlockDriverState *bs, int argc, char **argv); + + static const cmdinfo_t writev_cmd = { + .name = "writev", +@@ -886,7 +900,7 @@ static const cmdinfo_t writev_cmd = { + .help = writev_help, + }; + +-static int writev_f(int argc, char **argv) ++static int writev_f(BlockDriverState *bs, int argc, char **argv) + { + struct timeval t1, t2; + int Cflag = 0, qflag = 0; +@@ -936,13 +950,13 @@ static int writev_f(int argc, char **argv) + } + + nr_iov = argc - optind; +- buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern); ++ buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern); + if (buf == NULL) { + return 0; + } + + gettimeofday(&t1, NULL); +- cnt = do_aio_writev(&qiov, offset, &total); ++ cnt = do_aio_writev(bs, &qiov, offset, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { +@@ -983,7 +997,7 @@ static void multiwrite_help(void) + "\n"); + } + +-static int multiwrite_f(int argc, char **argv); ++static int multiwrite_f(BlockDriverState *bs, int argc, char **argv); + + static const cmdinfo_t multiwrite_cmd = { + .name = "multiwrite", +@@ -995,7 +1009,7 @@ static const cmdinfo_t multiwrite_cmd = { + .help = multiwrite_help, + }; + +-static int multiwrite_f(int argc, char **argv) ++static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) + { + struct timeval t1, t2; + int Cflag = 0, qflag = 0; +@@ -1076,7 +1090,7 @@ static int multiwrite_f(int argc, char **argv) + nr_iov = j - optind; + + /* Build request */ +- buf[i] = create_iovec(&qiovs[i], &argv[optind], nr_iov, pattern); ++ buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern); + if (buf[i] == NULL) { + goto out; + } +@@ -1094,7 +1108,7 @@ static int multiwrite_f(int argc, char **argv) + nr_reqs = i; + + gettimeofday(&t1, NULL); +- cnt = do_aio_multiwrite(reqs, nr_reqs, &total); ++ cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total); + gettimeofday(&t2, NULL); + + if (cnt < 0) { +@@ -1222,7 +1236,7 @@ static void aio_read_help(void) + "\n"); + } + +-static int aio_read_f(int argc, char **argv); ++static int aio_read_f(BlockDriverState *bs, int argc, char **argv); + + static const cmdinfo_t aio_read_cmd = { + .name = "aio_read", +@@ -1234,7 +1248,7 @@ static const cmdinfo_t aio_read_cmd = { + .help = aio_read_help, + }; + +-static int aio_read_f(int argc, char **argv) ++static int aio_read_f(BlockDriverState *bs, int argc, char **argv) + { + int nr_iov, c; + struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); +@@ -1285,7 +1299,7 @@ static int aio_read_f(int argc, char **argv) + } + + nr_iov = argc - optind; +- ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab); ++ ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab); + if (ctx->buf == NULL) { + g_free(ctx); + return 0; +@@ -1317,7 +1331,7 @@ static void aio_write_help(void) + "\n"); + } + +-static int aio_write_f(int argc, char **argv); ++static int aio_write_f(BlockDriverState *bs, int argc, char **argv); + + static const cmdinfo_t aio_write_cmd = { + .name = "aio_write", +@@ -1329,7 +1343,7 @@ static const cmdinfo_t aio_write_cmd = { + .help = aio_write_help, + }; + +-static int aio_write_f(int argc, char **argv) ++static int aio_write_f(BlockDriverState *bs, int argc, char **argv) + { + int nr_iov, c; + int pattern = 0xcd; +@@ -1377,7 +1391,7 @@ static int aio_write_f(int argc, char **argv) + } + + nr_iov = argc - optind; +- ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern); ++ ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern); + if (ctx->buf == NULL) { + g_free(ctx); + return 0; +@@ -1389,7 +1403,7 @@ static int aio_write_f(int argc, char **argv) + return 0; + } + +-static int aio_flush_f(int argc, char **argv) ++static int aio_flush_f(BlockDriverState *bs, int argc, char **argv) + { + bdrv_drain_all(); + return 0; +@@ -1401,7 +1415,7 @@ static const cmdinfo_t aio_flush_cmd = { + .oneline = "completes all outstanding aio requests" + }; + +-static int flush_f(int argc, char **argv) ++static int flush_f(BlockDriverState *bs, int argc, char **argv) + { + bdrv_flush(bs); + return 0; +@@ -1414,7 +1428,7 @@ static const cmdinfo_t flush_cmd = { + .oneline = "flush all in-core file state to disk", + }; + +-static int truncate_f(int argc, char **argv) ++static int truncate_f(BlockDriverState *bs, int argc, char **argv) + { + int64_t offset; + int ret; +@@ -1444,7 +1458,7 @@ static const cmdinfo_t truncate_cmd = { + .oneline = "truncates the current file at the given offset", + }; + +-static int length_f(int argc, char **argv) ++static int length_f(BlockDriverState *bs, int argc, char **argv) + { + int64_t size; + char s1[64]; +@@ -1469,7 +1483,7 @@ static const cmdinfo_t length_cmd = { + }; + + +-static int info_f(int argc, char **argv) ++static int info_f(BlockDriverState *bs, int argc, char **argv) + { + BlockDriverInfo bdi; + ImageInfoSpecific *spec_info; +@@ -1528,7 +1542,7 @@ static void discard_help(void) + "\n"); + } + +-static int discard_f(int argc, char **argv); ++static int discard_f(BlockDriverState *bs, int argc, char **argv); + + static const cmdinfo_t discard_cmd = { + .name = "discard", +@@ -1541,7 +1555,7 @@ static const cmdinfo_t discard_cmd = { + .help = discard_help, + }; + +-static int discard_f(int argc, char **argv) ++static int discard_f(BlockDriverState *bs, int argc, char **argv) + { + struct timeval t1, t2; + int Cflag = 0, qflag = 0; +@@ -1599,7 +1613,7 @@ out: + return 0; + } + +-static int alloc_f(int argc, char **argv) ++static int alloc_f(BlockDriverState *bs, int argc, char **argv) + { + int64_t offset, sector_num; + int nb_sectors, remaining; +@@ -1664,7 +1678,7 @@ static const cmdinfo_t alloc_cmd = { + .oneline = "checks if a sector is present in the file", + }; + +-static int map_f(int argc, char **argv) ++static int map_f(BlockDriverState *bs, int argc, char **argv) + { + int64_t offset; + int64_t nb_sectors; +@@ -1700,7 +1714,7 @@ static const cmdinfo_t map_cmd = { + .oneline = "prints the allocated areas of a file", + }; + +-static int break_f(int argc, char **argv) ++static int break_f(BlockDriverState *bs, int argc, char **argv) + { + int ret; + +@@ -1722,7 +1736,7 @@ static const cmdinfo_t break_cmd = { + "request as tag", + }; + +-static int resume_f(int argc, char **argv) ++static int resume_f(BlockDriverState *bs, int argc, char **argv) + { + int ret; + +@@ -1743,7 +1757,7 @@ static const cmdinfo_t resume_cmd = { + .oneline = "resumes the request tagged as tag", + }; + +-static int wait_break_f(int argc, char **argv) ++static int wait_break_f(BlockDriverState *bs, int argc, char **argv) + { + while (!bdrv_debug_is_suspended(bs, argv[1])) { + qemu_aio_wait(); +@@ -1761,7 +1775,7 @@ static const cmdinfo_t wait_break_cmd = { + .oneline = "waits for the suspension of a request", + }; + +-static int abort_f(int argc, char **argv) ++static int abort_f(BlockDriverState *bs, int argc, char **argv) + { + abort(); + } +@@ -1773,10 +1787,10 @@ static const cmdinfo_t abort_cmd = { + .oneline = "simulate a program crash using abort(3)", + }; + +-static int close_f(int argc, char **argv) ++static int close_f(BlockDriverState *bs, int argc, char **argv) + { + bdrv_unref(bs); +- bs = NULL; ++ qemuio_bs = NULL; + return 0; + } + +@@ -1793,7 +1807,7 @@ static void sleep_cb(void *opaque) + *expired = true; + } + +-static int sleep_f(int argc, char **argv) ++static int sleep_f(BlockDriverState *bs, int argc, char **argv) + { + char *endptr; + long ms; +@@ -1831,27 +1845,27 @@ static int openfile(char *name, int flags, int growable, QDict *opts) + { + Error *local_err = NULL; + +- if (bs) { ++ if (qemuio_bs) { + fprintf(stderr, "file open already, try 'help close'\n"); + return 1; + } + + if (growable) { +- if (bdrv_file_open(&bs, name, opts, flags, &local_err)) { ++ if (bdrv_file_open(&qemuio_bs, name, opts, flags, &local_err)) { + fprintf(stderr, "%s: can't open device %s: %s\n", progname, name, + error_get_pretty(local_err)); + error_free(local_err); + return 1; + } + } else { +- bs = bdrv_new("hda", &error_abort); ++ qemuio_bs = bdrv_new("hda", &error_abort); + +- if (bdrv_open(bs, name, opts, flags, NULL, &local_err) < 0) { ++ if (bdrv_open(qemuio_bs, name, opts, flags, NULL, &local_err) < 0) { + fprintf(stderr, "%s: can't open device %s: %s\n", progname, name, + error_get_pretty(local_err)); + error_free(local_err); +- bdrv_unref(bs); +- bs = NULL; ++ bdrv_unref(qemuio_bs); ++ qemuio_bs = NULL; + return 1; + } + } +@@ -1877,7 +1891,7 @@ static void open_help(void) + "\n"); + } + +-static int open_f(int argc, char **argv); ++static int open_f(BlockDriverState *bs, int argc, char **argv); + + static const cmdinfo_t open_cmd = { + .name = "open", +@@ -1900,7 +1914,7 @@ static QemuOptsList empty_opts = { + }, + }; + +-static int open_f(int argc, char **argv) ++static int open_f(BlockDriverState *bs, int argc, char **argv) + { + int flags = 0; + int readonly = 0; +@@ -1948,7 +1962,7 @@ static int open_f(int argc, char **argv) + return openfile(argv[optind], flags, growable, opts); + } + +-static int init_check_command(const cmdinfo_t *ct) ++static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) + { + if (ct->flags & CMD_FLAG_GLOBAL) { + return 1; +@@ -2117,8 +2131,8 @@ int main(int argc, char **argv) + */ + bdrv_drain_all(); + +- if (bs) { +- bdrv_unref(bs); ++ if (qemuio_bs) { ++ bdrv_unref(qemuio_bs); + } + return 0; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Factor-out-qemuio_command.patch b/SOURCES/kvm-qemu-io-Factor-out-qemuio_command.patch new file mode 100644 index 0000000..8e3dfa0 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Factor-out-qemuio_command.patch @@ -0,0 +1,163 @@ +From c73b87743086200c3f9ad485dcd4e71bdee27881 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:26 +0100 +Subject: [PATCH 07/27] qemu-io: Factor out qemuio_command + +RH-Author: John Snow +Message-id: <1448300320-7772-8-git-send-email-jsnow@redhat.com> +Patchwork-id: 68438 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 07/21] qemu-io: Factor out qemuio_command +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +It's duplicated code. Move it to qemu-io-cmds.c because it's not +dependent on any static data of the qemu-io tool. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit dd5832967ac3fe96bd5bf9f199639176998ead69) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + cmd.c | 43 +++++-------------------------------------- + cmd.h | 3 ++- + qemu-io-cmds.c | 24 ++++++++++++++++++++++++ + 3 files changed, 31 insertions(+), 39 deletions(-) + +diff --git a/cmd.c b/cmd.c +index d501aab..7ae978f 100644 +--- a/cmd.c ++++ b/cmd.c +@@ -138,28 +138,11 @@ static char *get_prompt(void); + + void command_loop(void) + { +- int c, i, done = 0, fetchable = 0, prompted = 0; ++ int i, done = 0, fetchable = 0, prompted = 0; + char *input; +- char **v; +- const cmdinfo_t *ct; + + for (i = 0; !done && i < ncmdline; i++) { +- input = strdup(cmdline[i]); +- if (!input) { +- fprintf(stderr, _("cannot strdup command '%s': %s\n"), +- cmdline[i], strerror(errno)); +- exit(1); +- } +- v = breakline(input, &c); +- if (c) { +- ct = find_command(v[0]); +- if (ct) { +- done = command(ct, c, v); +- } else { +- fprintf(stderr, _("command \"%s\" not found\n"), v[0]); +- } +- } +- doneline(input, v); ++ done = qemuio_command(cmdline[i]); + } + if (cmdline) { + g_free(cmdline); +@@ -179,20 +162,13 @@ void command_loop(void) + if (!fetchable) { + continue; + } ++ + input = fetchline(); + if (input == NULL) { + break; + } +- v = breakline(input, &c); +- if (c) { +- ct = find_command(v[0]); +- if (ct) { +- done = command(ct, c, v); +- } else { +- fprintf(stderr, _("command \"%s\" not found\n"), v[0]); +- } +- } +- doneline(input, v); ++ done = qemuio_command(input); ++ free(input); + + prompted = 0; + fetchable = 0; +@@ -328,15 +304,6 @@ char **breakline(char *input, int *count) + return rval; + } + +-void +-doneline( +- char *input, +- char **vec) +-{ +- free(input); +- free(vec); +-} +- + #define EXABYTES(x) ((long long)(x) << 60) + #define PETABYTES(x) ((long long)(x) << 50) + #define TERABYTES(x) ((long long)(x) << 40) +diff --git a/cmd.h b/cmd.h +index ccf6336..d676408 100644 +--- a/cmd.h ++++ b/cmd.h +@@ -59,7 +59,6 @@ int command(const cmdinfo_t *ci, int argc, char **argv); + + /* from input.h */ + char **breakline(char *input, int *count); +-void doneline(char *input, char **vec); + char *fetchline(void); + + void cvtstr(double value, char *str, size_t sz); +@@ -77,4 +76,6 @@ void timestr(struct timeval *tv, char *str, size_t sz, int flags); + + extern char *progname; + ++bool qemuio_command(const char *cmd); ++ + #endif /* __COMMAND_H__ */ +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index efa6070..09e4099 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -1824,6 +1824,30 @@ static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) + return 1; + } + ++bool qemuio_command(const char *cmd) ++{ ++ char *input; ++ const cmdinfo_t *ct; ++ char **v; ++ int c; ++ bool done = false; ++ ++ input = g_strdup(cmd); ++ v = breakline(input, &c); ++ if (c) { ++ ct = find_command(v[0]); ++ if (ct) { ++ done = command(ct, c, v); ++ } else { ++ fprintf(stderr, "command \"%s\" not found\n", v[0]); ++ } ++ } ++ g_free(input); ++ g_free(v); ++ ++ return done; ++} ++ + static void __attribute((constructor)) init_qemuio_commands(void) + { + /* initialize commands */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Handle-cvtnum-errors-in-alloc.patch b/SOURCES/kvm-qemu-io-Handle-cvtnum-errors-in-alloc.patch new file mode 100644 index 0000000..f3e78e1 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Handle-cvtnum-errors-in-alloc.patch @@ -0,0 +1,56 @@ +From 862f45e0ad5a70d10bffa435d5331c444874e4d2 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:23 +0100 +Subject: [PATCH 04/27] qemu-io: Handle cvtnum() errors in 'alloc' + +RH-Author: John Snow +Message-id: <1448300320-7772-5-git-send-email-jsnow@redhat.com> +Patchwork-id: 68431 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 04/21] qemu-io: Handle cvtnum() errors in 'alloc' +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit cf49a6a00c19cabf4006d4f82bef26345043e7b5) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-io.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/qemu-io.c b/qemu-io.c +index 3b5890e..e4fa2fc 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -1608,7 +1608,10 @@ static int alloc_f(int argc, char **argv) + int ret; + + offset = cvtnum(argv[1]); +- if (offset & 0x1ff) { ++ if (offset < 0) { ++ printf("non-numeric offset argument -- %s\n", argv[1]); ++ return 0; ++ } else if (offset & 0x1ff) { + printf("offset %" PRId64 " is not sector aligned\n", + offset); + return 0; +@@ -1616,6 +1619,10 @@ static int alloc_f(int argc, char **argv) + + if (argc == 3) { + nb_sectors = cvtnum(argv[2]); ++ if (nb_sectors < 0) { ++ printf("non-numeric length argument -- %s\n", argv[2]); ++ return 0; ++ } + } else { + nb_sectors = 1; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Interface-cleanup.patch b/SOURCES/kvm-qemu-io-Interface-cleanup.patch new file mode 100644 index 0000000..68430eb --- /dev/null +++ b/SOURCES/kvm-qemu-io-Interface-cleanup.patch @@ -0,0 +1,240 @@ +From 0dfb1b6f831f5b2a1fdf5e77330db3c95db2e464 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:33 +0100 +Subject: [PATCH 14/27] qemu-io: Interface cleanup + +RH-Author: John Snow +Message-id: <1448300320-7772-15-git-send-email-jsnow@redhat.com> +Patchwork-id: 68444 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 14/21] qemu-io: Interface cleanup +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Signed-off-by: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 3d21994f9c511cb63220fef5abea164b83fbb997) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina + +Conflicts: + qemu-io-cmds.c: include block/qapi.h context + qemu-io.c include block/qapi.h context + +Signed-off-by: John Snow +--- + cmd.h | 48 ------------------------------------------------ + include/qemu-io.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + qemu-io-cmds.c | 14 +++++++------- + qemu-io.c | 7 +++---- + 4 files changed, 56 insertions(+), 59 deletions(-) + delete mode 100644 cmd.h + create mode 100644 include/qemu-io.h + +diff --git a/cmd.h b/cmd.h +deleted file mode 100644 +index 9907795..0000000 +--- a/cmd.h ++++ /dev/null +@@ -1,48 +0,0 @@ +-/* +- * Copyright (c) 2000-2005 Silicon Graphics, Inc. +- * All Rights Reserved. +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation. +- * +- * This program is distributed in the hope that it would be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, see . +- */ +-#ifndef __COMMAND_H__ +-#define __COMMAND_H__ +- +-#include "qemu-common.h" +- +-#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ +- +-extern BlockDriverState *qemuio_bs; +- +-typedef int (*cfunc_t)(BlockDriverState *bs, int argc, char **argv); +-typedef void (*helpfunc_t)(void); +- +-typedef struct cmdinfo { +- const char *name; +- const char *altname; +- cfunc_t cfunc; +- int argmin; +- int argmax; +- int canpush; +- int flags; +- const char *args; +- const char *oneline; +- helpfunc_t help; +-} cmdinfo_t; +- +-void qemuio_add_command(const cmdinfo_t *ci); +- +-int qemuio_command_usage(const cmdinfo_t *ci); +- +-bool qemuio_command(const char *cmd); +- +-#endif /* __COMMAND_H__ */ +diff --git a/include/qemu-io.h b/include/qemu-io.h +new file mode 100644 +index 0000000..a418b46 +--- /dev/null ++++ b/include/qemu-io.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (c) 2000-2005 Silicon Graphics, Inc. ++ * All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#ifndef QEMU_IO_H ++#define QEMU_IO_H ++ ++#include "qemu-common.h" ++ ++#define CMD_FLAG_GLOBAL ((int)0x80000000) /* don't iterate "args" */ ++ ++typedef int (*cfunc_t)(BlockDriverState *bs, int argc, char **argv); ++typedef void (*helpfunc_t)(void); ++ ++typedef struct cmdinfo { ++ const char* name; ++ const char* altname; ++ cfunc_t cfunc; ++ int argmin; ++ int argmax; ++ int canpush; ++ int flags; ++ const char *args; ++ const char *oneline; ++ helpfunc_t help; ++} cmdinfo_t; ++ ++bool qemuio_command(BlockDriverState *bs, const char *cmd); ++ ++void qemuio_add_command(const cmdinfo_t *ci); ++int qemuio_command_usage(const cmdinfo_t *ci); ++ ++#endif /* QEMU_IO_H */ +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index 1db7fb9..1f21ce9 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -8,10 +8,9 @@ + * See the COPYING file in the top-level directory. + */ + +-#include "qemu-common.h" ++#include "qemu-io.h" + #include "block/block_int.h" + #include "block/qapi.h" +-#include "cmd.h" + + #define CMD_NOFILE_OK 0x01 + +@@ -51,11 +50,12 @@ static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) + return 1; + } + +-static int command(const cmdinfo_t *ct, int argc, char **argv) ++static int command(BlockDriverState *bs, const cmdinfo_t *ct, int argc, ++ char **argv) + { + char *cmd = argv[0]; + +- if (!init_check_command(qemuio_bs, ct)) { ++ if (!init_check_command(bs, ct)) { + return 0; + } + +@@ -76,7 +76,7 @@ static int command(const cmdinfo_t *ct, int argc, char **argv) + return 0; + } + optind = 0; +- return ct->cfunc(qemuio_bs, argc, argv); ++ return ct->cfunc(bs, argc, argv); + } + + static const cmdinfo_t *find_command(const char *cmd) +@@ -2084,7 +2084,7 @@ static const cmdinfo_t help_cmd = { + .oneline = "help for one or all commands", + }; + +-bool qemuio_command(const char *cmd) ++bool qemuio_command(BlockDriverState *bs, const char *cmd) + { + char *input; + const cmdinfo_t *ct; +@@ -2097,7 +2097,7 @@ bool qemuio_command(const char *cmd) + if (c) { + ct = find_command(v[0]); + if (ct) { +- done = command(ct, c, v); ++ done = command(bs, ct, c, v); + } else { + fprintf(stderr, "command \"%s\" not found\n", v[0]); + } +diff --git a/qemu-io.c b/qemu-io.c +index da9944e..e685808 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -14,13 +14,12 @@ + #include + #include + +-#include "qemu-common.h" ++#include "qemu-io.h" + #include "qemu/main-loop.h" + #include "qemu/option.h" + #include "qemu/config-file.h" + #include "block/block_int.h" + #include "block/qapi.h" +-#include "cmd.h" + #include "trace/control.h" + #include "qemu/timer.h" + +@@ -306,7 +305,7 @@ static void command_loop(void) + char *input; + + for (i = 0; !done && i < ncmdline; i++) { +- done = qemuio_command(cmdline[i]); ++ done = qemuio_command(qemuio_bs, cmdline[i]); + } + if (cmdline) { + g_free(cmdline); +@@ -331,7 +330,7 @@ static void command_loop(void) + if (input == NULL) { + break; + } +- done = qemuio_command(input); ++ done = qemuio_command(qemuio_bs, input); + g_free(input); + + prompted = 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Make-cvtnum-a-wrapper-around-strtosz_suffix.patch b/SOURCES/kvm-qemu-io-Make-cvtnum-a-wrapper-around-strtosz_suffix.patch new file mode 100644 index 0000000..2b4fbc7 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Make-cvtnum-a-wrapper-around-strtosz_suffix.patch @@ -0,0 +1,112 @@ +From 94787daf53d6eb2936704f7d9089b26cc5803699 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:22 +0100 +Subject: [PATCH 03/27] qemu-io: Make cvtnum() a wrapper around + strtosz_suffix() + +RH-Author: John Snow +Message-id: <1448300320-7772-4-git-send-email-jsnow@redhat.com> +Patchwork-id: 68432 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 03/21] qemu-io: Make cvtnum() a wrapper around strtosz_suffix() +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +No reason to implement the same thing multiple times. A nice side effect +is that fractional numbers like 0.5M can be used in qemu-io now. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit b6e356aa25c81d928e1c463292048d29cf25f04e) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + cmd.c | 37 ------------------------------------- + cmd.h | 1 - + qemu-io.c | 6 ++++++ + 3 files changed, 6 insertions(+), 38 deletions(-) + +diff --git a/cmd.c b/cmd.c +index 4e7579b..214c6f7 100644 +--- a/cmd.c ++++ b/cmd.c +@@ -344,43 +344,6 @@ doneline( + #define MEGABYTES(x) ((long long)(x) << 20) + #define KILOBYTES(x) ((long long)(x) << 10) + +-long long +-cvtnum( +- char *s) +-{ +- long long i; +- char *sp; +- int c; +- +- i = strtoll(s, &sp, 0); +- if (i == 0 && sp == s) +- return -1LL; +- if (*sp == '\0') +- return i; +- +- if (sp[1] != '\0') +- return -1LL; +- +- c = qemu_tolower(*sp); +- switch (c) { +- default: +- return i; +- case 'k': +- return KILOBYTES(i); +- case 'm': +- return MEGABYTES(i); +- case 'g': +- return GIGABYTES(i); +- case 't': +- return TERABYTES(i); +- case 'p': +- return PETABYTES(i); +- case 'e': +- return EXABYTES(i); +- } +- return -1LL; +-} +- + #define TO_EXABYTES(x) ((x) / EXABYTES(1)) + #define TO_PETABYTES(x) ((x) / PETABYTES(1)) + #define TO_TERABYTES(x) ((x) / TERABYTES(1)) +diff --git a/cmd.h b/cmd.h +index 8e6f753..4dcfe88 100644 +--- a/cmd.h ++++ b/cmd.h +@@ -58,7 +58,6 @@ char **breakline(char *input, int *count); + void doneline(char *input, char **vec); + char *fetchline(void); + +-long long cvtnum(char *s); + void cvtstr(double value, char *str, size_t sz); + + struct timeval tsub(struct timeval t1, struct timeval t2); +diff --git a/qemu-io.c b/qemu-io.c +index 9f66a78..3b5890e 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -33,6 +33,12 @@ static BlockDriverState *bs; + + static int misalign; + ++static int64_t cvtnum(const char *s) ++{ ++ char *end; ++ return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B); ++} ++ + /* + * Parse the pattern argument to various sub-commands. + * +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Move-command_loop-and-friends.patch b/SOURCES/kvm-qemu-io-Move-command_loop-and-friends.patch new file mode 100644 index 0000000..2ba730c --- /dev/null +++ b/SOURCES/kvm-qemu-io-Move-command_loop-and-friends.patch @@ -0,0 +1,369 @@ +From 828d09abacc6ae7f0643957301cc3ddee269d7a0 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:31 +0100 +Subject: [PATCH 12/27] qemu-io: Move command_loop() and friends + +RH-Author: John Snow +Message-id: <1448300320-7772-13-git-send-email-jsnow@redhat.com> +Patchwork-id: 68441 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 12/21] qemu-io: Move command_loop() and friends +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Signed-off-by: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit d1174f13e78e2f43f7ae33d59b62b0b94468c8db) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + cmd.c | 139 -------------------------------------------------------------- + cmd.h | 9 ---- + qemu-io.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 139 insertions(+), 148 deletions(-) + +diff --git a/cmd.c b/cmd.c +index 6616d61..26d38a8 100644 +--- a/cmd.c ++++ b/cmd.c +@@ -31,145 +31,6 @@ + + /* from libxcmd/command.c */ + +-static int ncmdline; +-static char **cmdline; +- +- +-void add_user_command(char *optarg) +-{ +- cmdline = g_realloc(cmdline, ++ncmdline * sizeof(char *)); +- cmdline[ncmdline-1] = optarg; +-} +- +-static void prep_fetchline(void *opaque) +-{ +- int *fetchable = opaque; +- +- qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); +- *fetchable= 1; +-} +- +-static char *get_prompt(void); +- +-void command_loop(void) +-{ +- int i, done = 0, fetchable = 0, prompted = 0; +- char *input; +- +- for (i = 0; !done && i < ncmdline; i++) { +- done = qemuio_command(cmdline[i]); +- } +- if (cmdline) { +- g_free(cmdline); +- return; +- } +- +- while (!done) { +- if (!prompted) { +- printf("%s", get_prompt()); +- fflush(stdout); +- qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable); +- prompted = 1; +- } +- +- main_loop_wait(false); +- +- if (!fetchable) { +- continue; +- } +- +- input = fetchline(); +- if (input == NULL) { +- break; +- } +- done = qemuio_command(input); +- free(input); +- +- prompted = 0; +- fetchable = 0; +- } +- qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); +-} +- +-/* from libxcmd/input.c */ +- +-#if defined(ENABLE_READLINE) +-# include +-# include +-#elif defined(ENABLE_EDITLINE) +-# include +-#endif +- +-static char * +-get_prompt(void) +-{ +- static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; +- +- if (!prompt[0]) +- snprintf(prompt, sizeof(prompt), "%s> ", progname); +- return prompt; +-} +- +-#if defined(ENABLE_READLINE) +-char * +-fetchline(void) +-{ +- char *line; +- +- line = readline(get_prompt()); +- if (line && *line) +- add_history(line); +- return line; +-} +-#elif defined(ENABLE_EDITLINE) +-static char *el_get_prompt(EditLine *e) { return get_prompt(); } +-char * +-fetchline(void) +-{ +- static EditLine *el; +- static History *hist; +- HistEvent hevent; +- char *line; +- int count; +- +- if (!el) { +- hist = history_init(); +- history(hist, &hevent, H_SETSIZE, 100); +- el = el_init(progname, stdin, stdout, stderr); +- el_source(el, NULL); +- el_set(el, EL_SIGNAL, 1); +- el_set(el, EL_PROMPT, el_get_prompt); +- el_set(el, EL_HIST, history, (const char *)hist); +- } +- line = strdup(el_gets(el, &count)); +- if (line) { +- if (count > 0) +- line[count-1] = '\0'; +- if (*line) +- history(hist, &hevent, H_ENTER, line); +- } +- return line; +-} +-#else +-# define MAXREADLINESZ 1024 +-char * +-fetchline(void) +-{ +- char *p, *line = malloc(MAXREADLINESZ); +- +- if (!line) +- return NULL; +- if (!fgets(line, MAXREADLINESZ, stdin)) { +- free(line); +- return NULL; +- } +- p = line + strlen(line); +- if (p != line && p[-1] == '\n') +- p[-1] = '\0'; +- return line; +-} +-#endif +- + #define EXABYTES(x) ((long long)(x) << 60) + #define PETABYTES(x) ((long long)(x) << 50) + #define TERABYTES(x) ((long long)(x) << 40) +diff --git a/cmd.h b/cmd.h +index 0d01a33..da0c7cf 100644 +--- a/cmd.h ++++ b/cmd.h +@@ -39,18 +39,11 @@ typedef struct cmdinfo { + helpfunc_t help; + } cmdinfo_t; + +-typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci); +- + void qemuio_add_command(const cmdinfo_t *ci); +-void add_user_command(char *optarg); +-void add_check_command(checkfunc_t cf); + +-void command_loop(void); + int qemuio_command_usage(const cmdinfo_t *ci); + + /* from input.h */ +-char *fetchline(void); +- + void cvtstr(double value, char *str, size_t sz); + + struct timeval tsub(struct timeval t1, struct timeval t2); +@@ -64,8 +57,6 @@ enum { + + void timestr(struct timeval *tv, char *str, size_t sz, int flags); + +-extern char *progname; +- + bool qemuio_command(const char *cmd); + + #endif /* __COMMAND_H__ */ +diff --git a/qemu-io.c b/qemu-io.c +index 97af39e..da9944e 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -34,6 +34,10 @@ BlockDriverState *qemuio_bs; + + extern int qemuio_misalign; + ++/* qemu-io commands passed using -c */ ++static int ncmdline; ++static char **cmdline; ++ + static int close_f(BlockDriverState *bs, int argc, char **argv) + { + bdrv_unref(bs); +@@ -207,6 +211,141 @@ static void usage(const char *name) + } + + ++#if defined(ENABLE_READLINE) ++# include ++# include ++#elif defined(ENABLE_EDITLINE) ++# include ++#endif ++ ++static char *get_prompt(void) ++{ ++ static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; ++ ++ if (!prompt[0]) { ++ snprintf(prompt, sizeof(prompt), "%s> ", progname); ++ } ++ ++ return prompt; ++} ++ ++#if defined(ENABLE_READLINE) ++static char *fetchline(void) ++{ ++ char *line = readline(get_prompt()); ++ if (line && *line) { ++ add_history(line); ++ } ++ return line; ++} ++#elif defined(ENABLE_EDITLINE) ++static char *el_get_prompt(EditLine *e) ++{ ++ return get_prompt(); ++} ++ ++static char *fetchline(void) ++{ ++ static EditLine *el; ++ static History *hist; ++ HistEvent hevent; ++ char *line; ++ int count; ++ ++ if (!el) { ++ hist = history_init(); ++ history(hist, &hevent, H_SETSIZE, 100); ++ el = el_init(progname, stdin, stdout, stderr); ++ el_source(el, NULL); ++ el_set(el, EL_SIGNAL, 1); ++ el_set(el, EL_PROMPT, el_get_prompt); ++ el_set(el, EL_HIST, history, (const char *)hist); ++ } ++ line = strdup(el_gets(el, &count)); ++ if (line) { ++ if (count > 0) { ++ line[count-1] = '\0'; ++ } ++ if (*line) { ++ history(hist, &hevent, H_ENTER, line); ++ } ++ } ++ return line; ++} ++#else ++# define MAXREADLINESZ 1024 ++static char *fetchline(void) ++{ ++ char *p, *line = g_malloc(MAXREADLINESZ); ++ ++ if (!fgets(line, MAXREADLINESZ, stdin)) { ++ g_free(line); ++ return NULL; ++ } ++ ++ p = line + strlen(line); ++ if (p != line && p[-1] == '\n') { ++ p[-1] = '\0'; ++ } ++ ++ return line; ++} ++#endif ++ ++static void prep_fetchline(void *opaque) ++{ ++ int *fetchable = opaque; ++ ++ qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); ++ *fetchable= 1; ++} ++ ++static void command_loop(void) ++{ ++ int i, done = 0, fetchable = 0, prompted = 0; ++ char *input; ++ ++ for (i = 0; !done && i < ncmdline; i++) { ++ done = qemuio_command(cmdline[i]); ++ } ++ if (cmdline) { ++ g_free(cmdline); ++ return; ++ } ++ ++ while (!done) { ++ if (!prompted) { ++ printf("%s", get_prompt()); ++ fflush(stdout); ++ qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable); ++ prompted = 1; ++ } ++ ++ main_loop_wait(false); ++ ++ if (!fetchable) { ++ continue; ++ } ++ ++ input = fetchline(); ++ if (input == NULL) { ++ break; ++ } ++ done = qemuio_command(input); ++ g_free(input); ++ ++ prompted = 0; ++ fetchable = 0; ++ } ++ qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); ++} ++ ++static void add_user_command(char *optarg) ++{ ++ cmdline = g_realloc(cmdline, ++ncmdline * sizeof(char *)); ++ cmdline[ncmdline-1] = optarg; ++} ++ + int main(int argc, char **argv) + { + int readonly = 0; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Move-functions-for-registering-and-running-c.patch b/SOURCES/kvm-qemu-io-Move-functions-for-registering-and-running-c.patch new file mode 100644 index 0000000..0284767 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Move-functions-for-registering-and-running-c.patch @@ -0,0 +1,551 @@ +From df682d833654f2f42595d6156341439644a8848d Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:30 +0100 +Subject: [PATCH 11/27] qemu-io: Move functions for registering and running + commands + +RH-Author: John Snow +Message-id: <1448300320-7772-12-git-send-email-jsnow@redhat.com> +Patchwork-id: 68439 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 11/21] qemu-io: Move functions for registering and running commands +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit c2cdf5c5892165cbe7d3567bff5930521bc52669) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina + +Conflicts: + qemu-io-cmds.c: Conflicts over sleep_f, again. + +Signed-off-by: John Snow +--- + cmd.c | 113 --------------------------------- + cmd.h | 11 +--- + qemu-io-cmds.c | 194 +++++++++++++++++++++++++++++++++++++++++---------------- + qemu-io.c | 10 +-- + 4 files changed, 149 insertions(+), 179 deletions(-) + +diff --git a/cmd.c b/cmd.c +index f6bf2c5..6616d61 100644 +--- a/cmd.c ++++ b/cmd.c +@@ -31,94 +31,9 @@ + + /* from libxcmd/command.c */ + +-cmdinfo_t *cmdtab; +-int ncmds; +- +-static checkfunc_t check_func; + static int ncmdline; + static char **cmdline; + +-static int +-compare(const void *a, const void *b) +-{ +- return strcmp(((const cmdinfo_t *)a)->name, +- ((const cmdinfo_t *)b)->name); +-} +- +-void add_command(const cmdinfo_t *ci) +-{ +- cmdtab = g_realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab)); +- cmdtab[ncmds - 1] = *ci; +- qsort(cmdtab, ncmds, sizeof(*cmdtab), compare); +-} +- +-static int +-check_command( +- const cmdinfo_t *ci) +-{ +- if (check_func) +- return check_func(qemuio_bs, ci); +- return 1; +-} +- +-void +-add_check_command( +- checkfunc_t cf) +-{ +- check_func = cf; +-} +- +-int +-command_usage( +- const cmdinfo_t *ci) +-{ +- printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); +- return 0; +-} +- +-int +-command( +- const cmdinfo_t *ct, +- int argc, +- char **argv) +-{ +- char *cmd = argv[0]; +- +- if (!check_command(ct)) +- return 0; +- +- if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) { +- if (ct->argmax == -1) +- fprintf(stderr, +- _("bad argument count %d to %s, expected at least %d arguments\n"), +- argc-1, cmd, ct->argmin); +- else if (ct->argmin == ct->argmax) +- fprintf(stderr, +- _("bad argument count %d to %s, expected %d arguments\n"), +- argc-1, cmd, ct->argmin); +- else +- fprintf(stderr, +- _("bad argument count %d to %s, expected between %d and %d arguments\n"), +- argc-1, cmd, ct->argmin, ct->argmax); +- return 0; +- } +- optind = 0; +- return ct->cfunc(qemuio_bs, argc, argv); +-} +- +-const cmdinfo_t * +-find_command( +- const char *cmd) +-{ +- cmdinfo_t *ct; +- +- for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { +- if (strcmp(ct->name, cmd) == 0 || +- (ct->altname && strcmp(ct->altname, cmd) == 0)) +- return (const cmdinfo_t *)ct; +- } +- return NULL; +-} + + void add_user_command(char *optarg) + { +@@ -255,34 +170,6 @@ fetchline(void) + } + #endif + +-char **breakline(char *input, int *count) +-{ +- int c = 0; +- char *p; +- char **rval = calloc(sizeof(char *), 1); +- char **tmp; +- +- while (rval && (p = qemu_strsep(&input, " ")) != NULL) { +- if (!*p) { +- continue; +- } +- c++; +- tmp = realloc(rval, sizeof(*rval) * (c + 1)); +- if (!tmp) { +- free(rval); +- rval = NULL; +- c = 0; +- break; +- } else { +- rval = tmp; +- } +- rval[c - 1] = p; +- rval[c] = NULL; +- } +- *count = c; +- return rval; +-} +- + #define EXABYTES(x) ((long long)(x) << 60) + #define PETABYTES(x) ((long long)(x) << 50) + #define TERABYTES(x) ((long long)(x) << 40) +diff --git a/cmd.h b/cmd.h +index 5b6f61b..0d01a33 100644 +--- a/cmd.h ++++ b/cmd.h +@@ -39,23 +39,16 @@ typedef struct cmdinfo { + helpfunc_t help; + } cmdinfo_t; + +-extern cmdinfo_t *cmdtab; +-extern int ncmds; +- + typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci); + +-void add_command(const cmdinfo_t *ci); ++void qemuio_add_command(const cmdinfo_t *ci); + void add_user_command(char *optarg); + void add_check_command(checkfunc_t cf); + +-const cmdinfo_t *find_command(const char *cmd); +- + void command_loop(void); +-int command_usage(const cmdinfo_t *ci); +-int command(const cmdinfo_t *ci, int argc, char **argv); ++int qemuio_command_usage(const cmdinfo_t *ci); + + /* from input.h */ +-char **breakline(char *input, int *count); + char *fetchline(void); + + void cvtstr(double value, char *str, size_t sz); +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index a8e891a..27a903f 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -17,6 +17,110 @@ + + int qemuio_misalign; + ++static cmdinfo_t *cmdtab; ++static int ncmds; ++ ++static int compare_cmdname(const void *a, const void *b) ++{ ++ return strcmp(((const cmdinfo_t *)a)->name, ++ ((const cmdinfo_t *)b)->name); ++} ++ ++void qemuio_add_command(const cmdinfo_t *ci) ++{ ++ cmdtab = g_realloc(cmdtab, ++ncmds * sizeof(*cmdtab)); ++ cmdtab[ncmds - 1] = *ci; ++ qsort(cmdtab, ncmds, sizeof(*cmdtab), compare_cmdname); ++} ++ ++int qemuio_command_usage(const cmdinfo_t *ci) ++{ ++ printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); ++ return 0; ++} ++ ++static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) ++{ ++ if (ct->flags & CMD_FLAG_GLOBAL) { ++ return 1; ++ } ++ if (!(ct->flags & CMD_NOFILE_OK) && !bs) { ++ fprintf(stderr, "no file open, try 'help open'\n"); ++ return 0; ++ } ++ return 1; ++} ++ ++static int command(const cmdinfo_t *ct, int argc, char **argv) ++{ ++ char *cmd = argv[0]; ++ ++ if (!init_check_command(qemuio_bs, ct)) { ++ return 0; ++ } ++ ++ if (argc - 1 < ct->argmin || (ct->argmax != -1 && argc - 1 > ct->argmax)) { ++ if (ct->argmax == -1) { ++ fprintf(stderr, ++ "bad argument count %d to %s, expected at least %d arguments\n", ++ argc-1, cmd, ct->argmin); ++ } else if (ct->argmin == ct->argmax) { ++ fprintf(stderr, ++ "bad argument count %d to %s, expected %d arguments\n", ++ argc-1, cmd, ct->argmin); ++ } else { ++ fprintf(stderr, ++ "bad argument count %d to %s, expected between %d and %d arguments\n", ++ argc-1, cmd, ct->argmin, ct->argmax); ++ } ++ return 0; ++ } ++ optind = 0; ++ return ct->cfunc(qemuio_bs, argc, argv); ++} ++ ++static const cmdinfo_t *find_command(const char *cmd) ++{ ++ cmdinfo_t *ct; ++ ++ for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { ++ if (strcmp(ct->name, cmd) == 0 || ++ (ct->altname && strcmp(ct->altname, cmd) == 0)) ++ { ++ return (const cmdinfo_t *)ct; ++ } ++ } ++ return NULL; ++} ++ ++static char **breakline(char *input, int *count) ++{ ++ int c = 0; ++ char *p; ++ char **rval = g_malloc0(sizeof(char *)); ++ char **tmp; ++ ++ while (rval && (p = qemu_strsep(&input, " ")) != NULL) { ++ if (!*p) { ++ continue; ++ } ++ c++; ++ tmp = g_realloc(rval, sizeof(*rval) * (c + 1)); ++ if (!tmp) { ++ g_free(rval); ++ rval = NULL; ++ c = 0; ++ break; ++ } else { ++ rval = tmp; ++ } ++ rval[c - 1] = p; ++ rval[c] = NULL; ++ } ++ *count = c; ++ return rval; ++} ++ + static int64_t cvtnum(const char *s) + { + char *end; +@@ -468,12 +572,12 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) + vflag = 1; + break; + default: +- return command_usage(&read_cmd); ++ return qemuio_command_usage(&read_cmd); + } + } + + if (optind != argc - 2) { +- return command_usage(&read_cmd); ++ return qemuio_command_usage(&read_cmd); + } + + if (bflag && pflag) { +@@ -495,7 +599,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) + } + + if (!Pflag && (lflag || sflag)) { +- return command_usage(&read_cmd); ++ return qemuio_command_usage(&read_cmd); + } + + if (!lflag) { +@@ -630,12 +734,12 @@ static int readv_f(BlockDriverState *bs, int argc, char **argv) + vflag = 1; + break; + default: +- return command_usage(&readv_cmd); ++ return qemuio_command_usage(&readv_cmd); + } + } + + if (optind > argc - 2) { +- return command_usage(&readv_cmd); ++ return qemuio_command_usage(&readv_cmd); + } + + +@@ -770,12 +874,12 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) + zflag = 1; + break; + default: +- return command_usage(&write_cmd); ++ return qemuio_command_usage(&write_cmd); + } + } + + if (optind != argc - 2) { +- return command_usage(&write_cmd); ++ return qemuio_command_usage(&write_cmd); + } + + if (bflag + pflag + zflag > 1) { +@@ -912,12 +1016,12 @@ static int writev_f(BlockDriverState *bs, int argc, char **argv) + } + break; + default: +- return command_usage(&writev_cmd); ++ return qemuio_command_usage(&writev_cmd); + } + } + + if (optind > argc - 2) { +- return command_usage(&writev_cmd); ++ return qemuio_command_usage(&writev_cmd); + } + + offset = cvtnum(argv[optind]); +@@ -1024,12 +1128,12 @@ static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) + } + break; + default: +- return command_usage(&writev_cmd); ++ return qemuio_command_usage(&writev_cmd); + } + } + + if (optind > argc - 2) { +- return command_usage(&writev_cmd); ++ return qemuio_command_usage(&writev_cmd); + } + + nr_reqs = 1; +@@ -1258,13 +1362,13 @@ static int aio_read_f(BlockDriverState *bs, int argc, char **argv) + break; + default: + g_free(ctx); +- return command_usage(&aio_read_cmd); ++ return qemuio_command_usage(&aio_read_cmd); + } + } + + if (optind > argc - 2) { + g_free(ctx); +- return command_usage(&aio_read_cmd); ++ return qemuio_command_usage(&aio_read_cmd); + } + + ctx->offset = cvtnum(argv[optind]); +@@ -1350,13 +1454,13 @@ static int aio_write_f(BlockDriverState *bs, int argc, char **argv) + break; + default: + g_free(ctx); +- return command_usage(&aio_write_cmd); ++ return qemuio_command_usage(&aio_write_cmd); + } + } + + if (optind > argc - 2) { + g_free(ctx); +- return command_usage(&aio_write_cmd); ++ return qemuio_command_usage(&aio_write_cmd); + } + + ctx->offset = cvtnum(argv[optind]); +@@ -1556,12 +1660,12 @@ static int discard_f(BlockDriverState *bs, int argc, char **argv) + qflag = 1; + break; + default: +- return command_usage(&discard_cmd); ++ return qemuio_command_usage(&discard_cmd); + } + } + + if (optind != argc - 2) { +- return command_usage(&discard_cmd); ++ return qemuio_command_usage(&discard_cmd); + } + + offset = cvtnum(argv[optind]); +@@ -1876,18 +1980,6 @@ static const cmdinfo_t help_cmd = { + .oneline = "help for one or all commands", + }; + +-static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) +-{ +- if (ct->flags & CMD_FLAG_GLOBAL) { +- return 1; +- } +- if (!(ct->flags & CMD_NOFILE_OK) && !bs) { +- fprintf(stderr, "no file open, try 'help open'\n"); +- return 0; +- } +- return 1; +-} +- + bool qemuio_command(const char *cmd) + { + char *input; +@@ -1915,27 +2007,25 @@ bool qemuio_command(const char *cmd) + static void __attribute((constructor)) init_qemuio_commands(void) + { + /* initialize commands */ +- add_command(&help_cmd); +- add_command(&read_cmd); +- add_command(&readv_cmd); +- add_command(&write_cmd); +- add_command(&writev_cmd); +- add_command(&multiwrite_cmd); +- add_command(&aio_read_cmd); +- add_command(&aio_write_cmd); +- add_command(&aio_flush_cmd); +- add_command(&flush_cmd); +- add_command(&truncate_cmd); +- add_command(&length_cmd); +- add_command(&info_cmd); +- add_command(&discard_cmd); +- add_command(&alloc_cmd); +- add_command(&map_cmd); +- add_command(&break_cmd); +- add_command(&resume_cmd); +- add_command(&wait_break_cmd); +- add_command(&abort_cmd); +- add_command(&sleep_cmd); +- +- add_check_command(init_check_command); ++ qemuio_add_command(&help_cmd); ++ qemuio_add_command(&read_cmd); ++ qemuio_add_command(&readv_cmd); ++ qemuio_add_command(&write_cmd); ++ qemuio_add_command(&writev_cmd); ++ qemuio_add_command(&multiwrite_cmd); ++ qemuio_add_command(&aio_read_cmd); ++ qemuio_add_command(&aio_write_cmd); ++ qemuio_add_command(&aio_flush_cmd); ++ qemuio_add_command(&flush_cmd); ++ qemuio_add_command(&truncate_cmd); ++ qemuio_add_command(&length_cmd); ++ qemuio_add_command(&info_cmd); ++ qemuio_add_command(&discard_cmd); ++ qemuio_add_command(&alloc_cmd); ++ qemuio_add_command(&map_cmd); ++ qemuio_add_command(&break_cmd); ++ qemuio_add_command(&resume_cmd); ++ qemuio_add_command(&wait_break_cmd); ++ qemuio_add_command(&abort_cmd); ++ qemuio_add_command(&sleep_cmd); + } +diff --git a/qemu-io.c b/qemu-io.c +index b86bfbf..97af39e 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -155,7 +155,7 @@ static int open_f(BlockDriverState *bs, int argc, char **argv) + qemu_opts_del(qopts); + break; + default: +- return command_usage(&open_cmd); ++ return qemuio_command_usage(&open_cmd); + } + } + +@@ -164,7 +164,7 @@ static int open_f(BlockDriverState *bs, int argc, char **argv) + } + + if (optind != argc - 1) { +- return command_usage(&open_cmd); ++ return qemuio_command_usage(&open_cmd); + } + + return openfile(argv[optind], flags, growable, opts); +@@ -300,9 +300,9 @@ int main(int argc, char **argv) + bdrv_init(); + + /* initialize commands */ +- add_command(&quit_cmd); +- add_command(&open_cmd); +- add_command(&close_cmd); ++ qemuio_add_command(&quit_cmd); ++ qemuio_add_command(&open_cmd); ++ qemuio_add_command(&close_cmd); + + /* open the device */ + if (!readonly) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Move-help-function.patch b/SOURCES/kvm-qemu-io-Move-help-function.patch new file mode 100644 index 0000000..42daa19 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Move-help-function.patch @@ -0,0 +1,223 @@ +From 8d6f59c923b536461df1aea18045535b090984fb Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:27 +0100 +Subject: [PATCH 08/27] qemu-io: Move 'help' function + +RH-Author: John Snow +Message-id: <1448300320-7772-9-git-send-email-jsnow@redhat.com> +Patchwork-id: 68435 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 08/21] qemu-io: Move 'help' function +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +No reason to treat it different from other commands. Move it to +qemu-io-cmds.c, adapt the coding style and register it like any other +command. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit f18a834a92f0b490cefeb71410f3f25b969d336f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina + +Conflicts: + qemu-io-cmds: patch context (from sleep_f) + +Signed-off-by: John Snow +--- + cmd.c | 79 ---------------------------------------------------------- + cmd.h | 1 - + qemu-io-cmds.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 65 insertions(+), 81 deletions(-) + +diff --git a/cmd.c b/cmd.c +index 7ae978f..2941ad3 100644 +--- a/cmd.c ++++ b/cmd.c +@@ -439,82 +439,3 @@ quit_init(void) + + add_command(&quit_cmd); + } +- +-/* from libxcmd/help.c */ +- +-static cmdinfo_t help_cmd; +-static void help_onecmd(const char *cmd, const cmdinfo_t *ct); +-static void help_oneline(const char *cmd, const cmdinfo_t *ct); +- +-static void +-help_all(void) +-{ +- const cmdinfo_t *ct; +- +- for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) +- help_oneline(ct->name, ct); +- printf(_("\nUse 'help commandname' for extended help.\n")); +-} +- +-static int +-help_f( +- BlockDriverState *bs, +- int argc, +- char **argv) +-{ +- const cmdinfo_t *ct; +- +- if (argc == 1) { +- help_all(); +- return 0; +- } +- ct = find_command(argv[1]); +- if (ct == NULL) { +- printf(_("command %s not found\n"), argv[1]); +- return 0; +- } +- help_onecmd(argv[1], ct); +- return 0; +-} +- +-static void +-help_onecmd( +- const char *cmd, +- const cmdinfo_t *ct) +-{ +- help_oneline(cmd, ct); +- if (ct->help) +- ct->help(); +-} +- +-static void +-help_oneline( +- const char *cmd, +- const cmdinfo_t *ct) +-{ +- if (cmd) +- printf("%s ", cmd); +- else { +- printf("%s ", ct->name); +- if (ct->altname) +- printf("(or %s) ", ct->altname); +- } +- if (ct->args) +- printf("%s ", ct->args); +- printf("-- %s\n", ct->oneline); +-} +- +-void +-help_init(void) +-{ +- help_cmd.name = _("help"); +- help_cmd.altname = _("?"); +- help_cmd.cfunc = help_f; +- help_cmd.argmin = 0; +- help_cmd.argmax = 1; +- help_cmd.flags = CMD_FLAG_GLOBAL; +- help_cmd.args = _("[command]"); +- help_cmd.oneline = _("help for one or all commands"); +- +- add_command(&help_cmd); +-} +diff --git a/cmd.h b/cmd.h +index d676408..89e7c6e 100644 +--- a/cmd.h ++++ b/cmd.h +@@ -42,7 +42,6 @@ typedef struct cmdinfo { + extern cmdinfo_t *cmdtab; + extern int ncmds; + +-void help_init(void); + void quit_init(void); + + typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci); +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index 09e4099..a8e891a 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -1811,6 +1811,70 @@ static const cmdinfo_t sleep_cmd = { + .oneline = "waits for the given value in milliseconds", + }; + ++static void help_oneline(const char *cmd, const cmdinfo_t *ct) ++{ ++ if (cmd) { ++ printf("%s ", cmd); ++ } else { ++ printf("%s ", ct->name); ++ if (ct->altname) { ++ printf("(or %s) ", ct->altname); ++ } ++ } ++ ++ if (ct->args) { ++ printf("%s ", ct->args); ++ } ++ printf("-- %s\n", ct->oneline); ++} ++ ++static void help_onecmd(const char *cmd, const cmdinfo_t *ct) ++{ ++ help_oneline(cmd, ct); ++ if (ct->help) { ++ ct->help(); ++ } ++} ++ ++static void help_all(void) ++{ ++ const cmdinfo_t *ct; ++ ++ for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { ++ help_oneline(ct->name, ct); ++ } ++ printf("\nUse 'help commandname' for extended help.\n"); ++} ++ ++static int help_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ const cmdinfo_t *ct; ++ ++ if (argc == 1) { ++ help_all(); ++ return 0; ++ } ++ ++ ct = find_command(argv[1]); ++ if (ct == NULL) { ++ printf("command %s not found\n", argv[1]); ++ return 0; ++ } ++ ++ help_onecmd(argv[1], ct); ++ return 0; ++} ++ ++static const cmdinfo_t help_cmd = { ++ .name = "help", ++ .altname = "?", ++ .cfunc = help_f, ++ .argmin = 0, ++ .argmax = 1, ++ .flags = CMD_FLAG_GLOBAL, ++ .args = "[command]", ++ .oneline = "help for one or all commands", ++}; + + static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) + { +@@ -1851,7 +1915,7 @@ bool qemuio_command(const char *cmd) + static void __attribute((constructor)) init_qemuio_commands(void) + { + /* initialize commands */ +- help_init(); ++ add_command(&help_cmd); + add_command(&read_cmd); + add_command(&readv_cmd); + add_command(&write_cmd); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Move-qemu_strsep-to-cutils.c.patch b/SOURCES/kvm-qemu-io-Move-qemu_strsep-to-cutils.c.patch new file mode 100644 index 0000000..743967c --- /dev/null +++ b/SOURCES/kvm-qemu-io-Move-qemu_strsep-to-cutils.c.patch @@ -0,0 +1,107 @@ +From 4ab2a72fcfc65bd78cf60e6e5a29e2189fddf877 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:29 +0100 +Subject: [PATCH 10/27] qemu-io: Move qemu_strsep() to cutils.c + +RH-Author: John Snow +Message-id: <1448300320-7772-11-git-send-email-jsnow@redhat.com> +Patchwork-id: 68440 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 10/21] qemu-io: Move qemu_strsep() to cutils.c +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit a38ed811474e953371f848233208c2026c2d1195) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + cmd.c | 21 --------------------- + include/qemu-common.h | 1 + + util/cutils.c | 21 +++++++++++++++++++++ + 3 files changed, 22 insertions(+), 21 deletions(-) + +diff --git a/cmd.c b/cmd.c +index 8496e74..f6bf2c5 100644 +--- a/cmd.c ++++ b/cmd.c +@@ -255,27 +255,6 @@ fetchline(void) + } + #endif + +-static char *qemu_strsep(char **input, const char *delim) +-{ +- char *result = *input; +- if (result != NULL) { +- char *p; +- +- for (p = result; *p != '\0'; p++) { +- if (strchr(delim, *p)) { +- break; +- } +- } +- if (*p == '\0') { +- *input = NULL; +- } else { +- *p = '\0'; +- *input = p + 1; +- } +- } +- return result; +-} +- + char **breakline(char *input, int *count) + { + int c = 0; +diff --git a/include/qemu-common.h b/include/qemu-common.h +index 67f57c9..8c1132c 100644 +--- a/include/qemu-common.h ++++ b/include/qemu-common.h +@@ -161,6 +161,7 @@ char *pstrcat(char *buf, int buf_size, const char *s); + int strstart(const char *str, const char *val, const char **ptr); + int stristart(const char *str, const char *val, const char **ptr); + int qemu_strnlen(const char *s, int max_len); ++char *qemu_strsep(char **input, const char *delim); + time_t mktimegm(struct tm *tm); + int qemu_fls(int i); + int qemu_fdatasync(int fd); +diff --git a/util/cutils.c b/util/cutils.c +index 8f28896..0116fcd 100644 +--- a/util/cutils.c ++++ b/util/cutils.c +@@ -107,6 +107,27 @@ int qemu_strnlen(const char *s, int max_len) + return i; + } + ++char *qemu_strsep(char **input, const char *delim) ++{ ++ char *result = *input; ++ if (result != NULL) { ++ char *p; ++ ++ for (p = result; *p != '\0'; p++) { ++ if (strchr(delim, *p)) { ++ break; ++ } ++ } ++ if (*p == '\0') { ++ *input = NULL; ++ } else { ++ *p = '\0'; ++ *input = p + 1; ++ } ++ } ++ return result; ++} ++ + time_t mktimegm(struct tm *tm) + { + time_t t; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Move-quit-function.patch b/SOURCES/kvm-qemu-io-Move-quit-function.patch new file mode 100644 index 0000000..e6442be --- /dev/null +++ b/SOURCES/kvm-qemu-io-Move-quit-function.patch @@ -0,0 +1,119 @@ +From 6ea43a1599b4abdfe480d6e963dbbafa9339601a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:28 +0100 +Subject: [PATCH 09/27] qemu-io: Move 'quit' function + +RH-Author: John Snow +Message-id: <1448300320-7772-10-git-send-email-jsnow@redhat.com> +Patchwork-id: 68436 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 09/21] qemu-io: Move 'quit' function +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +This one only makes sense in the context of the qemu-io tool, so move it +to qemu-io.c. Adapt coding style and register it like other commands. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit e681be7eca0143fe7259ce8233fe5dd8898d072f) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + cmd.c | 29 ----------------------------- + cmd.h | 2 -- + qemu-io.c | 17 ++++++++++++++++- + 3 files changed, 16 insertions(+), 32 deletions(-) + +diff --git a/cmd.c b/cmd.c +index 2941ad3..8496e74 100644 +--- a/cmd.c ++++ b/cmd.c +@@ -410,32 +410,3 @@ timestr( + snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000)); + } + } +- +- +-/* from libxcmd/quit.c */ +- +-static cmdinfo_t quit_cmd; +- +-/* ARGSUSED */ +-static int +-quit_f( +- BlockDriverState *bs, +- int argc, +- char **argv) +-{ +- return 1; +-} +- +-void +-quit_init(void) +-{ +- quit_cmd.name = _("quit"); +- quit_cmd.altname = _("q"); +- quit_cmd.cfunc = quit_f; +- quit_cmd.argmin = -1; +- quit_cmd.argmax = -1; +- quit_cmd.flags = CMD_FLAG_GLOBAL; +- quit_cmd.oneline = _("exit the program"); +- +- add_command(&quit_cmd); +-} +diff --git a/cmd.h b/cmd.h +index 89e7c6e..5b6f61b 100644 +--- a/cmd.h ++++ b/cmd.h +@@ -42,8 +42,6 @@ typedef struct cmdinfo { + extern cmdinfo_t *cmdtab; + extern int ncmds; + +-void quit_init(void); +- + typedef int (*checkfunc_t)(BlockDriverState *bs, const cmdinfo_t *ci); + + void add_command(const cmdinfo_t *ci); +diff --git a/qemu-io.c b/qemu-io.c +index 4f1c808..b86bfbf 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -170,6 +170,21 @@ static int open_f(BlockDriverState *bs, int argc, char **argv) + return openfile(argv[optind], flags, growable, opts); + } + ++static int quit_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ return 1; ++} ++ ++static const cmdinfo_t quit_cmd = { ++ .name = "quit", ++ .altname = "q", ++ .cfunc = quit_f, ++ .argmin = -1, ++ .argmax = -1, ++ .flags = CMD_FLAG_GLOBAL, ++ .oneline = "exit the program", ++}; ++ + static void usage(const char *name) + { + printf( +@@ -285,7 +300,7 @@ int main(int argc, char **argv) + bdrv_init(); + + /* initialize commands */ +- quit_init(); ++ add_command(&quit_cmd); + add_command(&open_cmd); + add_command(&close_cmd); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Move-remaining-helpers-from-cmd.c.patch b/SOURCES/kvm-qemu-io-Move-remaining-helpers-from-cmd.c.patch new file mode 100644 index 0000000..89354b4 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Move-remaining-helpers-from-cmd.c.patch @@ -0,0 +1,330 @@ +From f0e4ec43a0a3af6f1e385fae17527ed76cdb00e4 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:32 +0100 +Subject: [PATCH 13/27] qemu-io: Move remaining helpers from cmd.c + +RH-Author: John Snow +Message-id: <1448300320-7772-14-git-send-email-jsnow@redhat.com> +Patchwork-id: 68437 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 13/21] qemu-io: Move remaining helpers from cmd.c +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Signed-off-by: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 0b613881ae8fc59359b3d91e666fea6c9b1e731b) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + Makefile | 2 +- + cmd.c | 139 --------------------------------------------------------- + cmd.h | 14 ------ + qemu-io-cmds.c | 104 ++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 105 insertions(+), 154 deletions(-) + delete mode 100644 cmd.c + +diff --git a/Makefile b/Makefile +index f28ce29..f403057 100644 +--- a/Makefile ++++ b/Makefile +@@ -205,7 +205,7 @@ qemu-img.o: qemu-img-cmds.h + + qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a + qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a +-qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a ++qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o $(block-obj-y) libqemuutil.a libqemustub.a + + qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o + +diff --git a/cmd.c b/cmd.c +deleted file mode 100644 +index 26d38a8..0000000 +--- a/cmd.c ++++ /dev/null +@@ -1,139 +0,0 @@ +-/* +- * Copyright (c) 2003-2005 Silicon Graphics, Inc. +- * All Rights Reserved. +- * +- * This program is free software; you can redistribute it and/or +- * modify it under the terms of the GNU General Public License as +- * published by the Free Software Foundation. +- * +- * This program is distributed in the hope that it would be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, see . +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "cmd.h" +-#include "block/aio.h" +-#include "qemu/main-loop.h" +- +-#define _(x) x /* not gettext support yet */ +- +-/* from libxcmd/command.c */ +- +-#define EXABYTES(x) ((long long)(x) << 60) +-#define PETABYTES(x) ((long long)(x) << 50) +-#define TERABYTES(x) ((long long)(x) << 40) +-#define GIGABYTES(x) ((long long)(x) << 30) +-#define MEGABYTES(x) ((long long)(x) << 20) +-#define KILOBYTES(x) ((long long)(x) << 10) +- +-#define TO_EXABYTES(x) ((x) / EXABYTES(1)) +-#define TO_PETABYTES(x) ((x) / PETABYTES(1)) +-#define TO_TERABYTES(x) ((x) / TERABYTES(1)) +-#define TO_GIGABYTES(x) ((x) / GIGABYTES(1)) +-#define TO_MEGABYTES(x) ((x) / MEGABYTES(1)) +-#define TO_KILOBYTES(x) ((x) / KILOBYTES(1)) +- +-void +-cvtstr( +- double value, +- char *str, +- size_t size) +-{ +- char *trim; +- const char *suffix; +- +- if (value >= EXABYTES(1)) { +- suffix = " EiB"; +- snprintf(str, size - 4, "%.3f", TO_EXABYTES(value)); +- } else if (value >= PETABYTES(1)) { +- suffix = " PiB"; +- snprintf(str, size - 4, "%.3f", TO_PETABYTES(value)); +- } else if (value >= TERABYTES(1)) { +- suffix = " TiB"; +- snprintf(str, size - 4, "%.3f", TO_TERABYTES(value)); +- } else if (value >= GIGABYTES(1)) { +- suffix = " GiB"; +- snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value)); +- } else if (value >= MEGABYTES(1)) { +- suffix = " MiB"; +- snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value)); +- } else if (value >= KILOBYTES(1)) { +- suffix = " KiB"; +- snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value)); +- } else { +- suffix = " bytes"; +- snprintf(str, size - 6, "%f", value); +- } +- +- trim = strstr(str, ".000"); +- if (trim) { +- strcpy(trim, suffix); +- } else { +- strcat(str, suffix); +- } +-} +- +-struct timeval +-tsub(struct timeval t1, struct timeval t2) +-{ +- t1.tv_usec -= t2.tv_usec; +- if (t1.tv_usec < 0) { +- t1.tv_usec += 1000000; +- t1.tv_sec--; +- } +- t1.tv_sec -= t2.tv_sec; +- return t1; +-} +- +-double +-tdiv(double value, struct timeval tv) +-{ +- return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); +-} +- +-#define HOURS(sec) ((sec) / (60 * 60)) +-#define MINUTES(sec) (((sec) % (60 * 60)) / 60) +-#define SECONDS(sec) ((sec) % 60) +- +-void +-timestr( +- struct timeval *tv, +- char *ts, +- size_t size, +- int format) +-{ +- double usec = (double)tv->tv_usec / 1000000.0; +- +- if (format & TERSE_FIXED_TIME) { +- if (!HOURS(tv->tv_sec)) { +- snprintf(ts, size, "%u:%02u.%02u", +- (unsigned int) MINUTES(tv->tv_sec), +- (unsigned int) SECONDS(tv->tv_sec), +- (unsigned int) (usec * 100)); +- return; +- } +- format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ +- } +- +- if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { +- snprintf(ts, size, "%u:%02u:%02u.%02u", +- (unsigned int) HOURS(tv->tv_sec), +- (unsigned int) MINUTES(tv->tv_sec), +- (unsigned int) SECONDS(tv->tv_sec), +- (unsigned int) (usec * 100)); +- } else { +- snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000)); +- } +-} +diff --git a/cmd.h b/cmd.h +index da0c7cf..9907795 100644 +--- a/cmd.h ++++ b/cmd.h +@@ -43,20 +43,6 @@ void qemuio_add_command(const cmdinfo_t *ci); + + int qemuio_command_usage(const cmdinfo_t *ci); + +-/* from input.h */ +-void cvtstr(double value, char *str, size_t sz); +- +-struct timeval tsub(struct timeval t1, struct timeval t2); +-double tdiv(double value, struct timeval tv); +- +-enum { +- DEFAULT_TIME = 0x0, +- TERSE_FIXED_TIME = 0x1, +- VERBOSE_FIXED_TIME = 0x2 +-}; +- +-void timestr(struct timeval *tv, char *str, size_t sz, int flags); +- + bool qemuio_command(const char *cmd); + + #endif /* __COMMAND_H__ */ +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index 27a903f..1db7fb9 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -127,6 +127,110 @@ static int64_t cvtnum(const char *s) + return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B); + } + ++#define EXABYTES(x) ((long long)(x) << 60) ++#define PETABYTES(x) ((long long)(x) << 50) ++#define TERABYTES(x) ((long long)(x) << 40) ++#define GIGABYTES(x) ((long long)(x) << 30) ++#define MEGABYTES(x) ((long long)(x) << 20) ++#define KILOBYTES(x) ((long long)(x) << 10) ++ ++#define TO_EXABYTES(x) ((x) / EXABYTES(1)) ++#define TO_PETABYTES(x) ((x) / PETABYTES(1)) ++#define TO_TERABYTES(x) ((x) / TERABYTES(1)) ++#define TO_GIGABYTES(x) ((x) / GIGABYTES(1)) ++#define TO_MEGABYTES(x) ((x) / MEGABYTES(1)) ++#define TO_KILOBYTES(x) ((x) / KILOBYTES(1)) ++ ++static void cvtstr(double value, char *str, size_t size) ++{ ++ char *trim; ++ const char *suffix; ++ ++ if (value >= EXABYTES(1)) { ++ suffix = " EiB"; ++ snprintf(str, size - 4, "%.3f", TO_EXABYTES(value)); ++ } else if (value >= PETABYTES(1)) { ++ suffix = " PiB"; ++ snprintf(str, size - 4, "%.3f", TO_PETABYTES(value)); ++ } else if (value >= TERABYTES(1)) { ++ suffix = " TiB"; ++ snprintf(str, size - 4, "%.3f", TO_TERABYTES(value)); ++ } else if (value >= GIGABYTES(1)) { ++ suffix = " GiB"; ++ snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value)); ++ } else if (value >= MEGABYTES(1)) { ++ suffix = " MiB"; ++ snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value)); ++ } else if (value >= KILOBYTES(1)) { ++ suffix = " KiB"; ++ snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value)); ++ } else { ++ suffix = " bytes"; ++ snprintf(str, size - 6, "%f", value); ++ } ++ ++ trim = strstr(str, ".000"); ++ if (trim) { ++ strcpy(trim, suffix); ++ } else { ++ strcat(str, suffix); ++ } ++} ++ ++ ++ ++static struct timeval tsub(struct timeval t1, struct timeval t2) ++{ ++ t1.tv_usec -= t2.tv_usec; ++ if (t1.tv_usec < 0) { ++ t1.tv_usec += 1000000; ++ t1.tv_sec--; ++ } ++ t1.tv_sec -= t2.tv_sec; ++ return t1; ++} ++ ++static double tdiv(double value, struct timeval tv) ++{ ++ return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0)); ++} ++ ++#define HOURS(sec) ((sec) / (60 * 60)) ++#define MINUTES(sec) (((sec) % (60 * 60)) / 60) ++#define SECONDS(sec) ((sec) % 60) ++ ++enum { ++ DEFAULT_TIME = 0x0, ++ TERSE_FIXED_TIME = 0x1, ++ VERBOSE_FIXED_TIME = 0x2, ++}; ++ ++static void timestr(struct timeval *tv, char *ts, size_t size, int format) ++{ ++ double usec = (double)tv->tv_usec / 1000000.0; ++ ++ if (format & TERSE_FIXED_TIME) { ++ if (!HOURS(tv->tv_sec)) { ++ snprintf(ts, size, "%u:%02u.%02u", ++ (unsigned int) MINUTES(tv->tv_sec), ++ (unsigned int) SECONDS(tv->tv_sec), ++ (unsigned int) (usec * 100)); ++ return; ++ } ++ format |= VERBOSE_FIXED_TIME; /* fallback if hours needed */ ++ } ++ ++ if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) { ++ snprintf(ts, size, "%u:%02u:%02u.%02u", ++ (unsigned int) HOURS(tv->tv_sec), ++ (unsigned int) MINUTES(tv->tv_sec), ++ (unsigned int) SECONDS(tv->tv_sec), ++ (unsigned int) (usec * 100)); ++ } else { ++ snprintf(ts, size, "0.%04u sec", (unsigned int) (usec * 10000)); ++ } ++} ++ + /* + * Parse the pattern argument to various sub-commands. + * +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Remove-unused-args_command.patch b/SOURCES/kvm-qemu-io-Remove-unused-args_command.patch new file mode 100644 index 0000000..a005944 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Remove-unused-args_command.patch @@ -0,0 +1,141 @@ +From d16c34d6dc39a159326efda97101aed3c1481812 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:20 +0100 +Subject: [PATCH 01/27] qemu-io: Remove unused args_command + +RH-Author: John Snow +Message-id: <1448300320-7772-2-git-send-email-jsnow@redhat.com> +Patchwork-id: 68429 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 01/21] qemu-io: Remove unused args_command +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +The original intention seems to be something with handling multiple +images at once, but this has never been implemented and the only +function ever registered is implemented to make everything behave like a +"global" command. Just do that unconditionally now. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit a23818f4ff3d7981f49453b739f589e4205930b5) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + cmd.c | 28 ++-------------------------- + cmd.h | 2 -- + qemu-io.c | 10 ---------- + 3 files changed, 2 insertions(+), 38 deletions(-) + +diff --git a/cmd.c b/cmd.c +index 10a8688..4e7579b 100644 +--- a/cmd.c ++++ b/cmd.c +@@ -34,7 +34,6 @@ + cmdinfo_t *cmdtab; + int ncmds; + +-static argsfunc_t args_func; + static checkfunc_t check_func; + static int ncmdline; + static char **cmdline; +@@ -127,22 +126,6 @@ void add_user_command(char *optarg) + cmdline[ncmdline-1] = optarg; + } + +-static int +-args_command( +- int index) +-{ +- if (args_func) +- return args_func(index); +- return 0; +-} +- +-void +-add_args_command( +- argsfunc_t af) +-{ +- args_func = af; +-} +- + static void prep_fetchline(void *opaque) + { + int *fetchable = opaque; +@@ -155,7 +138,7 @@ static char *get_prompt(void); + + void command_loop(void) + { +- int c, i, j = 0, done = 0, fetchable = 0, prompted = 0; ++ int c, i, done = 0, fetchable = 0, prompted = 0; + char *input; + char **v; + const cmdinfo_t *ct; +@@ -171,14 +154,7 @@ void command_loop(void) + if (c) { + ct = find_command(v[0]); + if (ct) { +- if (ct->flags & CMD_FLAG_GLOBAL) { +- done = command(ct, c, v); +- } else { +- j = 0; +- while (!done && (j = args_command(j))) { +- done = command(ct, c, v); +- } +- } ++ done = command(ct, c, v); + } else { + fprintf(stderr, _("command \"%s\" not found\n"), v[0]); + } +diff --git a/cmd.h b/cmd.h +index b763b19..8e6f753 100644 +--- a/cmd.h ++++ b/cmd.h +@@ -41,12 +41,10 @@ extern int ncmds; + void help_init(void); + void quit_init(void); + +-typedef int (*argsfunc_t)(int index); + typedef int (*checkfunc_t)(const cmdinfo_t *ci); + + void add_command(const cmdinfo_t *ci); + void add_user_command(char *optarg); +-void add_args_command(argsfunc_t af); + void add_check_command(checkfunc_t cf); + + const cmdinfo_t *find_command(const char *cmd); +diff --git a/qemu-io.c b/qemu-io.c +index cc89947..9f66a78 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -1935,15 +1935,6 @@ static int open_f(int argc, char **argv) + return openfile(argv[optind], flags, growable, opts); + } + +-static int init_args_command(int index) +-{ +- /* only one device allowed so far */ +- if (index >= 1) { +- return 0; +- } +- return ++index; +-} +- + static int init_check_command(const cmdinfo_t *ct) + { + if (ct->flags & CMD_FLAG_GLOBAL) { +@@ -2096,7 +2087,6 @@ int main(int argc, char **argv) + add_command(&abort_cmd); + add_command(&sleep_cmd); + +- add_args_command(init_args_command); + add_check_command(init_check_command); + + /* open the device */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Split-off-commands-to-qemu-io-cmds.c.patch b/SOURCES/kvm-qemu-io-Split-off-commands-to-qemu-io-cmds.c.patch new file mode 100644 index 0000000..957b8c7 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Split-off-commands-to-qemu-io-cmds.c.patch @@ -0,0 +1,3789 @@ +From 9bd448e0f256ac9327363a0f370b9616d967e986 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:25 +0100 +Subject: [PATCH 06/27] qemu-io: Split off commands to qemu-io-cmds.c + +RH-Author: John Snow +Message-id: <1448300320-7772-7-git-send-email-jsnow@redhat.com> +Patchwork-id: 68434 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 06/21] qemu-io: Split off commands to qemu-io-cmds.c +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +This is the implementation of all qemu-io commands that make sense to be +called from the qemu monitor, i.e. everything except open, close and +quit. + +Signed-off-by: Kevin Wolf +Reviewed-by: Eric Blake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 797ac58cb2093ab9192d8998a1fef85d87cc8661) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina + +Conflicts: + qemu-io.c: Minor differences, but as this is code motion, + The code motion had to be re-done to preserve + any backported changes. + qemu-io-cmds.c: re-created from downstream qemu-io.c. + +Signed-off-by: John Snow +--- + Makefile | 2 +- + qemu-io-cmds.c | 1853 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + qemu-io.c | 1831 +------------------------------------------------------ + 3 files changed, 1856 insertions(+), 1830 deletions(-) + create mode 100644 qemu-io-cmds.c + +diff --git a/Makefile b/Makefile +index 8407945..f28ce29 100644 +--- a/Makefile ++++ b/Makefile +@@ -205,7 +205,7 @@ qemu-img.o: qemu-img-cmds.h + + qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a + qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a +-qemu-io$(EXESUF): qemu-io.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a ++qemu-io$(EXESUF): qemu-io.o qemu-io-cmds.o cmd.o $(block-obj-y) libqemuutil.a libqemustub.a + + qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o + +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +new file mode 100644 +index 0000000..efa6070 +--- /dev/null ++++ b/qemu-io-cmds.c +@@ -0,0 +1,1853 @@ ++/* ++ * Command line utility to exercise the QEMU I/O path. ++ * ++ * Copyright (C) 2009 Red Hat, Inc. ++ * Copyright (c) 2003-2005 Silicon Graphics, Inc. ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#include "qemu-common.h" ++#include "block/block_int.h" ++#include "block/qapi.h" ++#include "cmd.h" ++ ++#define CMD_NOFILE_OK 0x01 ++ ++int qemuio_misalign; ++ ++static int64_t cvtnum(const char *s) ++{ ++ char *end; ++ return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B); ++} ++ ++/* ++ * Parse the pattern argument to various sub-commands. ++ * ++ * Because the pattern is used as an argument to memset it must evaluate ++ * to an unsigned integer that fits into a single byte. ++ */ ++static int parse_pattern(const char *arg) ++{ ++ char *endptr = NULL; ++ long pattern; ++ ++ pattern = strtol(arg, &endptr, 0); ++ if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') { ++ printf("%s is not a valid pattern byte\n", arg); ++ return -1; ++ } ++ ++ return pattern; ++} ++ ++/* ++ * Memory allocation helpers. ++ * ++ * Make sure memory is aligned by default, or purposefully misaligned if ++ * that is specified on the command line. ++ */ ++ ++#define MISALIGN_OFFSET 16 ++static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern) ++{ ++ void *buf; ++ ++ if (qemuio_misalign) { ++ len += MISALIGN_OFFSET; ++ } ++ buf = qemu_blockalign(bs, len); ++ memset(buf, pattern, len); ++ if (qemuio_misalign) { ++ buf += MISALIGN_OFFSET; ++ } ++ return buf; ++} ++ ++static void qemu_io_free(void *p) ++{ ++ if (qemuio_misalign) { ++ p -= MISALIGN_OFFSET; ++ } ++ qemu_vfree(p); ++} ++ ++static void dump_buffer(const void *buffer, int64_t offset, int len) ++{ ++ int i, j; ++ const uint8_t *p; ++ ++ for (i = 0, p = buffer; i < len; i += 16) { ++ const uint8_t *s = p; ++ ++ printf("%08" PRIx64 ": ", offset + i); ++ for (j = 0; j < 16 && i + j < len; j++, p++) { ++ printf("%02x ", *p); ++ } ++ printf(" "); ++ for (j = 0; j < 16 && i + j < len; j++, s++) { ++ if (isalnum(*s)) { ++ printf("%c", *s); ++ } else { ++ printf("."); ++ } ++ } ++ printf("\n"); ++ } ++} ++ ++static void print_report(const char *op, struct timeval *t, int64_t offset, ++ int count, int total, int cnt, int Cflag) ++{ ++ char s1[64], s2[64], ts[64]; ++ ++ timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0); ++ if (!Cflag) { ++ cvtstr((double)total, s1, sizeof(s1)); ++ cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); ++ printf("%s %d/%d bytes at offset %" PRId64 "\n", ++ op, total, count, offset); ++ printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", ++ s1, cnt, ts, s2, tdiv((double)cnt, *t)); ++ } else {/* bytes,ops,time,bytes/sec,ops/sec */ ++ printf("%d,%d,%s,%.3f,%.3f\n", ++ total, cnt, ts, ++ tdiv((double)total, *t), ++ tdiv((double)cnt, *t)); ++ } ++} ++ ++/* ++ * Parse multiple length statements for vectored I/O, and construct an I/O ++ * vector matching it. ++ */ ++static void * ++create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov, ++ int pattern) ++{ ++ size_t *sizes = g_new0(size_t, nr_iov); ++ size_t count = 0; ++ void *buf = NULL; ++ void *p; ++ int i; ++ ++ for (i = 0; i < nr_iov; i++) { ++ char *arg = argv[i]; ++ int64_t len; ++ ++ len = cvtnum(arg); ++ if (len < 0) { ++ printf("non-numeric length argument -- %s\n", arg); ++ goto fail; ++ } ++ ++ /* should be SIZE_T_MAX, but that doesn't exist */ ++ if (len > INT_MAX) { ++ printf("too large length argument -- %s\n", arg); ++ goto fail; ++ } ++ ++ if (len & 0x1ff) { ++ printf("length argument %" PRId64 ++ " is not sector aligned\n", len); ++ goto fail; ++ } ++ ++ sizes[i] = len; ++ count += len; ++ } ++ ++ qemu_iovec_init(qiov, nr_iov); ++ ++ buf = p = qemu_io_alloc(bs, count, pattern); ++ ++ for (i = 0; i < nr_iov; i++) { ++ qemu_iovec_add(qiov, p, sizes[i]); ++ p += sizes[i]; ++ } ++ ++fail: ++ g_free(sizes); ++ return buf; ++} ++ ++static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count, ++ int *total) ++{ ++ int ret; ++ ++ ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); ++ if (ret < 0) { ++ return ret; ++ } ++ *total = count; ++ return 1; ++} ++ ++static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count, ++ int *total) ++{ ++ int ret; ++ ++ ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); ++ if (ret < 0) { ++ return ret; ++ } ++ *total = count; ++ return 1; ++} ++ ++static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count, ++ int *total) ++{ ++ *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); ++ if (*total < 0) { ++ return *total; ++ } ++ return 1; ++} ++ ++static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count, ++ int *total) ++{ ++ *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); ++ if (*total < 0) { ++ return *total; ++ } ++ return 1; ++} ++ ++typedef struct { ++ BlockDriverState *bs; ++ int64_t offset; ++ int count; ++ int *total; ++ int ret; ++ bool done; ++} CoWriteZeroes; ++ ++static void coroutine_fn co_write_zeroes_entry(void *opaque) ++{ ++ CoWriteZeroes *data = opaque; ++ ++ data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE, ++ data->count / BDRV_SECTOR_SIZE, 0); ++ data->done = true; ++ if (data->ret < 0) { ++ *data->total = data->ret; ++ return; ++ } ++ ++ *data->total = data->count; ++} ++ ++static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, ++ int *total) ++{ ++ Coroutine *co; ++ CoWriteZeroes data = { ++ .bs = bs, ++ .offset = offset, ++ .count = count, ++ .total = total, ++ .done = false, ++ }; ++ ++ co = qemu_coroutine_create(co_write_zeroes_entry); ++ qemu_coroutine_enter(co, &data); ++ while (!data.done) { ++ qemu_aio_wait(); ++ } ++ if (data.ret < 0) { ++ return data.ret; ++ } else { ++ return 1; ++ } ++} ++ ++static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset, ++ int count, int *total) ++{ ++ int ret; ++ ++ ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9); ++ if (ret < 0) { ++ return ret; ++ } ++ *total = count; ++ return 1; ++} ++ ++static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset, ++ int count, int *total) ++{ ++ *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); ++ if (*total < 0) { ++ return *total; ++ } ++ return 1; ++} ++ ++static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset, ++ int count, int *total) ++{ ++ *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); ++ if (*total < 0) { ++ return *total; ++ } ++ return 1; ++} ++ ++#define NOT_DONE 0x7fffffff ++static void aio_rw_done(void *opaque, int ret) ++{ ++ *(int *)opaque = ret; ++} ++ ++static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov, ++ int64_t offset, int *total) ++{ ++ int async_ret = NOT_DONE; ++ ++ bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, ++ aio_rw_done, &async_ret); ++ while (async_ret == NOT_DONE) { ++ main_loop_wait(false); ++ } ++ ++ *total = qiov->size; ++ return async_ret < 0 ? async_ret : 1; ++} ++ ++static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov, ++ int64_t offset, int *total) ++{ ++ int async_ret = NOT_DONE; ++ ++ bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, ++ aio_rw_done, &async_ret); ++ while (async_ret == NOT_DONE) { ++ main_loop_wait(false); ++ } ++ ++ *total = qiov->size; ++ return async_ret < 0 ? async_ret : 1; ++} ++ ++struct multiwrite_async_ret { ++ int num_done; ++ int error; ++}; ++ ++static void multiwrite_cb(void *opaque, int ret) ++{ ++ struct multiwrite_async_ret *async_ret = opaque; ++ ++ async_ret->num_done++; ++ if (ret < 0) { ++ async_ret->error = ret; ++ } ++} ++ ++static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs, ++ int num_reqs, int *total) ++{ ++ int i, ret; ++ struct multiwrite_async_ret async_ret = { ++ .num_done = 0, ++ .error = 0, ++ }; ++ ++ *total = 0; ++ for (i = 0; i < num_reqs; i++) { ++ reqs[i].cb = multiwrite_cb; ++ reqs[i].opaque = &async_ret; ++ *total += reqs[i].qiov->size; ++ } ++ ++ ret = bdrv_aio_multiwrite(bs, reqs, num_reqs); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ while (async_ret.num_done < num_reqs) { ++ main_loop_wait(false); ++ } ++ ++ return async_ret.error < 0 ? async_ret.error : 1; ++} ++ ++static void read_help(void) ++{ ++ printf( ++"\n" ++" reads a range of bytes from the given offset\n" ++"\n" ++" Example:\n" ++" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n" ++"\n" ++" Reads a segment of the currently open file, optionally dumping it to the\n" ++" standard output stream (with -v option) for subsequent inspection.\n" ++" -b, -- read from the VM state rather than the virtual disk\n" ++" -C, -- report statistics in a machine parsable format\n" ++" -l, -- length for pattern verification (only with -P)\n" ++" -p, -- use bdrv_pread to read the file\n" ++" -P, -- use a pattern to verify read data\n" ++" -q, -- quiet mode, do not show I/O statistics\n" ++" -s, -- start offset for pattern verification (only with -P)\n" ++" -v, -- dump buffer to standard output\n" ++"\n"); ++} ++ ++static int read_f(BlockDriverState *bs, int argc, char **argv); ++ ++static const cmdinfo_t read_cmd = { ++ .name = "read", ++ .altname = "r", ++ .cfunc = read_f, ++ .argmin = 2, ++ .argmax = -1, ++ .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len", ++ .oneline = "reads a number of bytes at a specified offset", ++ .help = read_help, ++}; ++ ++static int read_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ struct timeval t1, t2; ++ int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; ++ int Pflag = 0, sflag = 0, lflag = 0, bflag = 0; ++ int c, cnt; ++ char *buf; ++ int64_t offset; ++ int count; ++ /* Some compilers get confused and warn if this is not initialized. */ ++ int total = 0; ++ int pattern = 0, pattern_offset = 0, pattern_count = 0; ++ ++ while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) { ++ switch (c) { ++ case 'b': ++ bflag = 1; ++ break; ++ case 'C': ++ Cflag = 1; ++ break; ++ case 'l': ++ lflag = 1; ++ pattern_count = cvtnum(optarg); ++ if (pattern_count < 0) { ++ printf("non-numeric length argument -- %s\n", optarg); ++ return 0; ++ } ++ break; ++ case 'p': ++ pflag = 1; ++ break; ++ case 'P': ++ Pflag = 1; ++ pattern = parse_pattern(optarg); ++ if (pattern < 0) { ++ return 0; ++ } ++ break; ++ case 'q': ++ qflag = 1; ++ break; ++ case 's': ++ sflag = 1; ++ pattern_offset = cvtnum(optarg); ++ if (pattern_offset < 0) { ++ printf("non-numeric length argument -- %s\n", optarg); ++ return 0; ++ } ++ break; ++ case 'v': ++ vflag = 1; ++ break; ++ default: ++ return command_usage(&read_cmd); ++ } ++ } ++ ++ if (optind != argc - 2) { ++ return command_usage(&read_cmd); ++ } ++ ++ if (bflag && pflag) { ++ printf("-b and -p cannot be specified at the same time\n"); ++ return 0; ++ } ++ ++ offset = cvtnum(argv[optind]); ++ if (offset < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ return 0; ++ } ++ ++ optind++; ++ count = cvtnum(argv[optind]); ++ if (count < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ return 0; ++ } ++ ++ if (!Pflag && (lflag || sflag)) { ++ return command_usage(&read_cmd); ++ } ++ ++ if (!lflag) { ++ pattern_count = count - pattern_offset; ++ } ++ ++ if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { ++ printf("pattern verification range exceeds end of read data\n"); ++ return 0; ++ } ++ ++ if (!pflag) { ++ if (offset & 0x1ff) { ++ printf("offset %" PRId64 " is not sector aligned\n", ++ offset); ++ return 0; ++ } ++ if (count & 0x1ff) { ++ printf("count %d is not sector aligned\n", ++ count); ++ return 0; ++ } ++ } ++ ++ buf = qemu_io_alloc(bs, count, 0xab); ++ ++ gettimeofday(&t1, NULL); ++ if (pflag) { ++ cnt = do_pread(bs, buf, offset, count, &total); ++ } else if (bflag) { ++ cnt = do_load_vmstate(bs, buf, offset, count, &total); ++ } else { ++ cnt = do_read(bs, buf, offset, count, &total); ++ } ++ gettimeofday(&t2, NULL); ++ ++ if (cnt < 0) { ++ printf("read failed: %s\n", strerror(-cnt)); ++ goto out; ++ } ++ ++ if (Pflag) { ++ void *cmp_buf = g_malloc(pattern_count); ++ memset(cmp_buf, pattern, pattern_count); ++ if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { ++ printf("Pattern verification failed at offset %" ++ PRId64 ", %d bytes\n", ++ offset + pattern_offset, pattern_count); ++ } ++ g_free(cmp_buf); ++ } ++ ++ if (qflag) { ++ goto out; ++ } ++ ++ if (vflag) { ++ dump_buffer(buf, offset, count); ++ } ++ ++ /* Finally, report back -- -C gives a parsable format */ ++ t2 = tsub(t2, t1); ++ print_report("read", &t2, offset, count, total, cnt, Cflag); ++ ++out: ++ qemu_io_free(buf); ++ ++ return 0; ++} ++ ++static void readv_help(void) ++{ ++ printf( ++"\n" ++" reads a range of bytes from the given offset into multiple buffers\n" ++"\n" ++" Example:\n" ++" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" ++"\n" ++" Reads a segment of the currently open file, optionally dumping it to the\n" ++" standard output stream (with -v option) for subsequent inspection.\n" ++" Uses multiple iovec buffers if more than one byte range is specified.\n" ++" -C, -- report statistics in a machine parsable format\n" ++" -P, -- use a pattern to verify read data\n" ++" -v, -- dump buffer to standard output\n" ++" -q, -- quiet mode, do not show I/O statistics\n" ++"\n"); ++} ++ ++static int readv_f(BlockDriverState *bs, int argc, char **argv); ++ ++static const cmdinfo_t readv_cmd = { ++ .name = "readv", ++ .cfunc = readv_f, ++ .argmin = 2, ++ .argmax = -1, ++ .args = "[-Cqv] [-P pattern ] off len [len..]", ++ .oneline = "reads a number of bytes at a specified offset", ++ .help = readv_help, ++}; ++ ++static int readv_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ struct timeval t1, t2; ++ int Cflag = 0, qflag = 0, vflag = 0; ++ int c, cnt; ++ char *buf; ++ int64_t offset; ++ /* Some compilers get confused and warn if this is not initialized. */ ++ int total = 0; ++ int nr_iov; ++ QEMUIOVector qiov; ++ int pattern = 0; ++ int Pflag = 0; ++ ++ while ((c = getopt(argc, argv, "CP:qv")) != EOF) { ++ switch (c) { ++ case 'C': ++ Cflag = 1; ++ break; ++ case 'P': ++ Pflag = 1; ++ pattern = parse_pattern(optarg); ++ if (pattern < 0) { ++ return 0; ++ } ++ break; ++ case 'q': ++ qflag = 1; ++ break; ++ case 'v': ++ vflag = 1; ++ break; ++ default: ++ return command_usage(&readv_cmd); ++ } ++ } ++ ++ if (optind > argc - 2) { ++ return command_usage(&readv_cmd); ++ } ++ ++ ++ offset = cvtnum(argv[optind]); ++ if (offset < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ return 0; ++ } ++ optind++; ++ ++ if (offset & 0x1ff) { ++ printf("offset %" PRId64 " is not sector aligned\n", ++ offset); ++ return 0; ++ } ++ ++ nr_iov = argc - optind; ++ buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab); ++ if (buf == NULL) { ++ return 0; ++ } ++ ++ gettimeofday(&t1, NULL); ++ cnt = do_aio_readv(bs, &qiov, offset, &total); ++ gettimeofday(&t2, NULL); ++ ++ if (cnt < 0) { ++ printf("readv failed: %s\n", strerror(-cnt)); ++ goto out; ++ } ++ ++ if (Pflag) { ++ void *cmp_buf = g_malloc(qiov.size); ++ memset(cmp_buf, pattern, qiov.size); ++ if (memcmp(buf, cmp_buf, qiov.size)) { ++ printf("Pattern verification failed at offset %" ++ PRId64 ", %zd bytes\n", offset, qiov.size); ++ } ++ g_free(cmp_buf); ++ } ++ ++ if (qflag) { ++ goto out; ++ } ++ ++ if (vflag) { ++ dump_buffer(buf, offset, qiov.size); ++ } ++ ++ /* Finally, report back -- -C gives a parsable format */ ++ t2 = tsub(t2, t1); ++ print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); ++ ++out: ++ qemu_iovec_destroy(&qiov); ++ qemu_io_free(buf); ++ return 0; ++} ++ ++static void write_help(void) ++{ ++ printf( ++"\n" ++" writes a range of bytes from the given offset\n" ++"\n" ++" Example:\n" ++" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n" ++"\n" ++" Writes into a segment of the currently open file, using a buffer\n" ++" filled with a set pattern (0xcdcdcdcd).\n" ++" -b, -- write to the VM state rather than the virtual disk\n" ++" -c, -- write compressed data with bdrv_write_compressed\n" ++" -p, -- use bdrv_pwrite to write the file\n" ++" -P, -- use different pattern to fill file\n" ++" -C, -- report statistics in a machine parsable format\n" ++" -q, -- quiet mode, do not show I/O statistics\n" ++" -z, -- write zeroes using bdrv_co_write_zeroes\n" ++"\n"); ++} ++ ++static int write_f(BlockDriverState *bs, int argc, char **argv); ++ ++static const cmdinfo_t write_cmd = { ++ .name = "write", ++ .altname = "w", ++ .cfunc = write_f, ++ .argmin = 2, ++ .argmax = -1, ++ .args = "[-bcCpqz] [-P pattern ] off len", ++ .oneline = "writes a number of bytes at a specified offset", ++ .help = write_help, ++}; ++ ++static int write_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ struct timeval t1, t2; ++ int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0; ++ int cflag = 0; ++ int c, cnt; ++ char *buf = NULL; ++ int64_t offset; ++ int count; ++ /* Some compilers get confused and warn if this is not initialized. */ ++ int total = 0; ++ int pattern = 0xcd; ++ ++ while ((c = getopt(argc, argv, "bcCpP:qz")) != EOF) { ++ switch (c) { ++ case 'b': ++ bflag = 1; ++ break; ++ case 'c': ++ cflag = 1; ++ break; ++ case 'C': ++ Cflag = 1; ++ break; ++ case 'p': ++ pflag = 1; ++ break; ++ case 'P': ++ Pflag = 1; ++ pattern = parse_pattern(optarg); ++ if (pattern < 0) { ++ return 0; ++ } ++ break; ++ case 'q': ++ qflag = 1; ++ break; ++ case 'z': ++ zflag = 1; ++ break; ++ default: ++ return command_usage(&write_cmd); ++ } ++ } ++ ++ if (optind != argc - 2) { ++ return command_usage(&write_cmd); ++ } ++ ++ if (bflag + pflag + zflag > 1) { ++ printf("-b, -p, or -z cannot be specified at the same time\n"); ++ return 0; ++ } ++ ++ if (zflag && Pflag) { ++ printf("-z and -P cannot be specified at the same time\n"); ++ return 0; ++ } ++ ++ offset = cvtnum(argv[optind]); ++ if (offset < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ return 0; ++ } ++ ++ optind++; ++ count = cvtnum(argv[optind]); ++ if (count < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ return 0; ++ } ++ ++ if (!pflag) { ++ if (offset & 0x1ff) { ++ printf("offset %" PRId64 " is not sector aligned\n", ++ offset); ++ return 0; ++ } ++ ++ if (count & 0x1ff) { ++ printf("count %d is not sector aligned\n", ++ count); ++ return 0; ++ } ++ } ++ ++ if (!zflag) { ++ buf = qemu_io_alloc(bs, count, pattern); ++ } ++ ++ gettimeofday(&t1, NULL); ++ if (pflag) { ++ cnt = do_pwrite(bs, buf, offset, count, &total); ++ } else if (bflag) { ++ cnt = do_save_vmstate(bs, buf, offset, count, &total); ++ } else if (zflag) { ++ cnt = do_co_write_zeroes(bs, offset, count, &total); ++ } else if (cflag) { ++ cnt = do_write_compressed(bs, buf, offset, count, &total); ++ } else { ++ cnt = do_write(bs, buf, offset, count, &total); ++ } ++ gettimeofday(&t2, NULL); ++ ++ if (cnt < 0) { ++ printf("write failed: %s\n", strerror(-cnt)); ++ goto out; ++ } ++ ++ if (qflag) { ++ goto out; ++ } ++ ++ /* Finally, report back -- -C gives a parsable format */ ++ t2 = tsub(t2, t1); ++ print_report("wrote", &t2, offset, count, total, cnt, Cflag); ++ ++out: ++ if (!zflag) { ++ qemu_io_free(buf); ++ } ++ ++ return 0; ++} ++ ++static void ++writev_help(void) ++{ ++ printf( ++"\n" ++" writes a range of bytes from the given offset source from multiple buffers\n" ++"\n" ++" Example:\n" ++" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" ++"\n" ++" Writes into a segment of the currently open file, using a buffer\n" ++" filled with a set pattern (0xcdcdcdcd).\n" ++" -P, -- use different pattern to fill file\n" ++" -C, -- report statistics in a machine parsable format\n" ++" -q, -- quiet mode, do not show I/O statistics\n" ++"\n"); ++} ++ ++static int writev_f(BlockDriverState *bs, int argc, char **argv); ++ ++static const cmdinfo_t writev_cmd = { ++ .name = "writev", ++ .cfunc = writev_f, ++ .argmin = 2, ++ .argmax = -1, ++ .args = "[-Cq] [-P pattern ] off len [len..]", ++ .oneline = "writes a number of bytes at a specified offset", ++ .help = writev_help, ++}; ++ ++static int writev_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ struct timeval t1, t2; ++ int Cflag = 0, qflag = 0; ++ int c, cnt; ++ char *buf; ++ int64_t offset; ++ /* Some compilers get confused and warn if this is not initialized. */ ++ int total = 0; ++ int nr_iov; ++ int pattern = 0xcd; ++ QEMUIOVector qiov; ++ ++ while ((c = getopt(argc, argv, "CqP:")) != EOF) { ++ switch (c) { ++ case 'C': ++ Cflag = 1; ++ break; ++ case 'q': ++ qflag = 1; ++ break; ++ case 'P': ++ pattern = parse_pattern(optarg); ++ if (pattern < 0) { ++ return 0; ++ } ++ break; ++ default: ++ return command_usage(&writev_cmd); ++ } ++ } ++ ++ if (optind > argc - 2) { ++ return command_usage(&writev_cmd); ++ } ++ ++ offset = cvtnum(argv[optind]); ++ if (offset < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ return 0; ++ } ++ optind++; ++ ++ if (offset & 0x1ff) { ++ printf("offset %" PRId64 " is not sector aligned\n", ++ offset); ++ return 0; ++ } ++ ++ nr_iov = argc - optind; ++ buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern); ++ if (buf == NULL) { ++ return 0; ++ } ++ ++ gettimeofday(&t1, NULL); ++ cnt = do_aio_writev(bs, &qiov, offset, &total); ++ gettimeofday(&t2, NULL); ++ ++ if (cnt < 0) { ++ printf("writev failed: %s\n", strerror(-cnt)); ++ goto out; ++ } ++ ++ if (qflag) { ++ goto out; ++ } ++ ++ /* Finally, report back -- -C gives a parsable format */ ++ t2 = tsub(t2, t1); ++ print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); ++out: ++ qemu_iovec_destroy(&qiov); ++ qemu_io_free(buf); ++ return 0; ++} ++ ++static void multiwrite_help(void) ++{ ++ printf( ++"\n" ++" writes a range of bytes from the given offset source from multiple buffers,\n" ++" in a batch of requests that may be merged by qemu\n" ++"\n" ++" Example:\n" ++" 'multiwrite 512 1k 1k ; 4k 1k'\n" ++" writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n" ++"\n" ++" Writes into a segment of the currently open file, using a buffer\n" ++" filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n" ++" by one for each request contained in the multiwrite command.\n" ++" -P, -- use different pattern to fill file\n" ++" -C, -- report statistics in a machine parsable format\n" ++" -q, -- quiet mode, do not show I/O statistics\n" ++"\n"); ++} ++ ++static int multiwrite_f(BlockDriverState *bs, int argc, char **argv); ++ ++static const cmdinfo_t multiwrite_cmd = { ++ .name = "multiwrite", ++ .cfunc = multiwrite_f, ++ .argmin = 2, ++ .argmax = -1, ++ .args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]", ++ .oneline = "issues multiple write requests at once", ++ .help = multiwrite_help, ++}; ++ ++static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ struct timeval t1, t2; ++ int Cflag = 0, qflag = 0; ++ int c, cnt; ++ char **buf; ++ int64_t offset, first_offset = 0; ++ /* Some compilers get confused and warn if this is not initialized. */ ++ int total = 0; ++ int nr_iov; ++ int nr_reqs; ++ int pattern = 0xcd; ++ QEMUIOVector *qiovs; ++ int i; ++ BlockRequest *reqs; ++ ++ while ((c = getopt(argc, argv, "CqP:")) != EOF) { ++ switch (c) { ++ case 'C': ++ Cflag = 1; ++ break; ++ case 'q': ++ qflag = 1; ++ break; ++ case 'P': ++ pattern = parse_pattern(optarg); ++ if (pattern < 0) { ++ return 0; ++ } ++ break; ++ default: ++ return command_usage(&writev_cmd); ++ } ++ } ++ ++ if (optind > argc - 2) { ++ return command_usage(&writev_cmd); ++ } ++ ++ nr_reqs = 1; ++ for (i = optind; i < argc; i++) { ++ if (!strcmp(argv[i], ";")) { ++ nr_reqs++; ++ } ++ } ++ ++ reqs = g_malloc0(nr_reqs * sizeof(*reqs)); ++ buf = g_malloc0(nr_reqs * sizeof(*buf)); ++ qiovs = g_malloc(nr_reqs * sizeof(*qiovs)); ++ ++ for (i = 0; i < nr_reqs && optind < argc; i++) { ++ int j; ++ ++ /* Read the offset of the request */ ++ offset = cvtnum(argv[optind]); ++ if (offset < 0) { ++ printf("non-numeric offset argument -- %s\n", argv[optind]); ++ goto out; ++ } ++ optind++; ++ ++ if (offset & 0x1ff) { ++ printf("offset %lld is not sector aligned\n", ++ (long long)offset); ++ goto out; ++ } ++ ++ if (i == 0) { ++ first_offset = offset; ++ } ++ ++ /* Read lengths for qiov entries */ ++ for (j = optind; j < argc; j++) { ++ if (!strcmp(argv[j], ";")) { ++ break; ++ } ++ } ++ ++ nr_iov = j - optind; ++ ++ /* Build request */ ++ buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern); ++ if (buf[i] == NULL) { ++ goto out; ++ } ++ ++ reqs[i].qiov = &qiovs[i]; ++ reqs[i].sector = offset >> 9; ++ reqs[i].nb_sectors = reqs[i].qiov->size >> 9; ++ ++ optind = j + 1; ++ ++ pattern++; ++ } ++ ++ /* If there were empty requests at the end, ignore them */ ++ nr_reqs = i; ++ ++ gettimeofday(&t1, NULL); ++ cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total); ++ gettimeofday(&t2, NULL); ++ ++ if (cnt < 0) { ++ printf("aio_multiwrite failed: %s\n", strerror(-cnt)); ++ goto out; ++ } ++ ++ if (qflag) { ++ goto out; ++ } ++ ++ /* Finally, report back -- -C gives a parsable format */ ++ t2 = tsub(t2, t1); ++ print_report("wrote", &t2, first_offset, total, total, cnt, Cflag); ++out: ++ for (i = 0; i < nr_reqs; i++) { ++ qemu_io_free(buf[i]); ++ if (reqs[i].qiov != NULL) { ++ qemu_iovec_destroy(&qiovs[i]); ++ } ++ } ++ g_free(buf); ++ g_free(reqs); ++ g_free(qiovs); ++ return 0; ++} ++ ++struct aio_ctx { ++ QEMUIOVector qiov; ++ int64_t offset; ++ char *buf; ++ int qflag; ++ int vflag; ++ int Cflag; ++ int Pflag; ++ int pattern; ++ struct timeval t1; ++}; ++ ++static void aio_write_done(void *opaque, int ret) ++{ ++ struct aio_ctx *ctx = opaque; ++ struct timeval t2; ++ ++ gettimeofday(&t2, NULL); ++ ++ ++ if (ret < 0) { ++ printf("aio_write failed: %s\n", strerror(-ret)); ++ goto out; ++ } ++ ++ if (ctx->qflag) { ++ goto out; ++ } ++ ++ /* Finally, report back -- -C gives a parsable format */ ++ t2 = tsub(t2, ctx->t1); ++ print_report("wrote", &t2, ctx->offset, ctx->qiov.size, ++ ctx->qiov.size, 1, ctx->Cflag); ++out: ++ qemu_io_free(ctx->buf); ++ qemu_iovec_destroy(&ctx->qiov); ++ g_free(ctx); ++} ++ ++static void aio_read_done(void *opaque, int ret) ++{ ++ struct aio_ctx *ctx = opaque; ++ struct timeval t2; ++ ++ gettimeofday(&t2, NULL); ++ ++ if (ret < 0) { ++ printf("readv failed: %s\n", strerror(-ret)); ++ goto out; ++ } ++ ++ if (ctx->Pflag) { ++ void *cmp_buf = g_malloc(ctx->qiov.size); ++ ++ memset(cmp_buf, ctx->pattern, ctx->qiov.size); ++ if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { ++ printf("Pattern verification failed at offset %" ++ PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size); ++ } ++ g_free(cmp_buf); ++ } ++ ++ if (ctx->qflag) { ++ goto out; ++ } ++ ++ if (ctx->vflag) { ++ dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size); ++ } ++ ++ /* Finally, report back -- -C gives a parsable format */ ++ t2 = tsub(t2, ctx->t1); ++ print_report("read", &t2, ctx->offset, ctx->qiov.size, ++ ctx->qiov.size, 1, ctx->Cflag); ++out: ++ qemu_io_free(ctx->buf); ++ qemu_iovec_destroy(&ctx->qiov); ++ g_free(ctx); ++} ++ ++static void aio_read_help(void) ++{ ++ printf( ++"\n" ++" asynchronously reads a range of bytes from the given offset\n" ++"\n" ++" Example:\n" ++" 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" ++"\n" ++" Reads a segment of the currently open file, optionally dumping it to the\n" ++" standard output stream (with -v option) for subsequent inspection.\n" ++" The read is performed asynchronously and the aio_flush command must be\n" ++" used to ensure all outstanding aio requests have been completed.\n" ++" -C, -- report statistics in a machine parsable format\n" ++" -P, -- use a pattern to verify read data\n" ++" -v, -- dump buffer to standard output\n" ++" -q, -- quiet mode, do not show I/O statistics\n" ++"\n"); ++} ++ ++static int aio_read_f(BlockDriverState *bs, int argc, char **argv); ++ ++static const cmdinfo_t aio_read_cmd = { ++ .name = "aio_read", ++ .cfunc = aio_read_f, ++ .argmin = 2, ++ .argmax = -1, ++ .args = "[-Cqv] [-P pattern ] off len [len..]", ++ .oneline = "asynchronously reads a number of bytes", ++ .help = aio_read_help, ++}; ++ ++static int aio_read_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ int nr_iov, c; ++ struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); ++ ++ while ((c = getopt(argc, argv, "CP:qv")) != EOF) { ++ switch (c) { ++ case 'C': ++ ctx->Cflag = 1; ++ break; ++ case 'P': ++ ctx->Pflag = 1; ++ ctx->pattern = parse_pattern(optarg); ++ if (ctx->pattern < 0) { ++ g_free(ctx); ++ return 0; ++ } ++ break; ++ case 'q': ++ ctx->qflag = 1; ++ break; ++ case 'v': ++ ctx->vflag = 1; ++ break; ++ default: ++ g_free(ctx); ++ return command_usage(&aio_read_cmd); ++ } ++ } ++ ++ if (optind > argc - 2) { ++ g_free(ctx); ++ return command_usage(&aio_read_cmd); ++ } ++ ++ ctx->offset = cvtnum(argv[optind]); ++ if (ctx->offset < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ g_free(ctx); ++ return 0; ++ } ++ optind++; ++ ++ if (ctx->offset & 0x1ff) { ++ printf("offset %" PRId64 " is not sector aligned\n", ++ ctx->offset); ++ g_free(ctx); ++ return 0; ++ } ++ ++ nr_iov = argc - optind; ++ ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab); ++ if (ctx->buf == NULL) { ++ g_free(ctx); ++ return 0; ++ } ++ ++ gettimeofday(&ctx->t1, NULL); ++ bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, ++ ctx->qiov.size >> 9, aio_read_done, ctx); ++ return 0; ++} ++ ++static void aio_write_help(void) ++{ ++ printf( ++"\n" ++" asynchronously writes a range of bytes from the given offset source\n" ++" from multiple buffers\n" ++"\n" ++" Example:\n" ++" 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" ++"\n" ++" Writes into a segment of the currently open file, using a buffer\n" ++" filled with a set pattern (0xcdcdcdcd).\n" ++" The write is performed asynchronously and the aio_flush command must be\n" ++" used to ensure all outstanding aio requests have been completed.\n" ++" -P, -- use different pattern to fill file\n" ++" -C, -- report statistics in a machine parsable format\n" ++" -q, -- quiet mode, do not show I/O statistics\n" ++"\n"); ++} ++ ++static int aio_write_f(BlockDriverState *bs, int argc, char **argv); ++ ++static const cmdinfo_t aio_write_cmd = { ++ .name = "aio_write", ++ .cfunc = aio_write_f, ++ .argmin = 2, ++ .argmax = -1, ++ .args = "[-Cq] [-P pattern ] off len [len..]", ++ .oneline = "asynchronously writes a number of bytes", ++ .help = aio_write_help, ++}; ++ ++static int aio_write_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ int nr_iov, c; ++ int pattern = 0xcd; ++ struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); ++ ++ while ((c = getopt(argc, argv, "CqP:")) != EOF) { ++ switch (c) { ++ case 'C': ++ ctx->Cflag = 1; ++ break; ++ case 'q': ++ ctx->qflag = 1; ++ break; ++ case 'P': ++ pattern = parse_pattern(optarg); ++ if (pattern < 0) { ++ g_free(ctx); ++ return 0; ++ } ++ break; ++ default: ++ g_free(ctx); ++ return command_usage(&aio_write_cmd); ++ } ++ } ++ ++ if (optind > argc - 2) { ++ g_free(ctx); ++ return command_usage(&aio_write_cmd); ++ } ++ ++ ctx->offset = cvtnum(argv[optind]); ++ if (ctx->offset < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ g_free(ctx); ++ return 0; ++ } ++ optind++; ++ ++ if (ctx->offset & 0x1ff) { ++ printf("offset %" PRId64 " is not sector aligned\n", ++ ctx->offset); ++ g_free(ctx); ++ return 0; ++ } ++ ++ nr_iov = argc - optind; ++ ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern); ++ if (ctx->buf == NULL) { ++ g_free(ctx); ++ return 0; ++ } ++ ++ gettimeofday(&ctx->t1, NULL); ++ bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, ++ ctx->qiov.size >> 9, aio_write_done, ctx); ++ return 0; ++} ++ ++static int aio_flush_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ bdrv_drain_all(); ++ return 0; ++} ++ ++static const cmdinfo_t aio_flush_cmd = { ++ .name = "aio_flush", ++ .cfunc = aio_flush_f, ++ .oneline = "completes all outstanding aio requests" ++}; ++ ++static int flush_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ bdrv_flush(bs); ++ return 0; ++} ++ ++static const cmdinfo_t flush_cmd = { ++ .name = "flush", ++ .altname = "f", ++ .cfunc = flush_f, ++ .oneline = "flush all in-core file state to disk", ++}; ++ ++static int truncate_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ int64_t offset; ++ int ret; ++ ++ offset = cvtnum(argv[1]); ++ if (offset < 0) { ++ printf("non-numeric truncate argument -- %s\n", argv[1]); ++ return 0; ++ } ++ ++ ret = bdrv_truncate(bs, offset); ++ if (ret < 0) { ++ printf("truncate: %s\n", strerror(-ret)); ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static const cmdinfo_t truncate_cmd = { ++ .name = "truncate", ++ .altname = "t", ++ .cfunc = truncate_f, ++ .argmin = 1, ++ .argmax = 1, ++ .args = "off", ++ .oneline = "truncates the current file at the given offset", ++}; ++ ++static int length_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ int64_t size; ++ char s1[64]; ++ ++ size = bdrv_getlength(bs); ++ if (size < 0) { ++ printf("getlength: %s\n", strerror(-size)); ++ return 0; ++ } ++ ++ cvtstr(size, s1, sizeof(s1)); ++ printf("%s\n", s1); ++ return 0; ++} ++ ++ ++static const cmdinfo_t length_cmd = { ++ .name = "length", ++ .altname = "l", ++ .cfunc = length_f, ++ .oneline = "gets the length of the current file", ++}; ++ ++ ++static int info_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ BlockDriverInfo bdi; ++ ImageInfoSpecific *spec_info; ++ char s1[64], s2[64]; ++ int ret; ++ ++ if (bs->drv && bs->drv->format_name) { ++ printf("format name: %s\n", bs->drv->format_name); ++ } ++ if (bs->drv && bs->drv->protocol_name) { ++ printf("format name: %s\n", bs->drv->protocol_name); ++ } ++ ++ ret = bdrv_get_info(bs, &bdi); ++ if (ret) { ++ return 0; ++ } ++ ++ cvtstr(bdi.cluster_size, s1, sizeof(s1)); ++ cvtstr(bdi.vm_state_offset, s2, sizeof(s2)); ++ ++ printf("cluster size: %s\n", s1); ++ printf("vm state offset: %s\n", s2); ++ ++ spec_info = bdrv_get_specific_info(bs); ++ if (spec_info) { ++ printf("Format specific information:\n"); ++ bdrv_image_info_specific_dump(fprintf, stdout, spec_info); ++ qapi_free_ImageInfoSpecific(spec_info); ++ } ++ ++ return 0; ++} ++ ++ ++ ++static const cmdinfo_t info_cmd = { ++ .name = "info", ++ .altname = "i", ++ .cfunc = info_f, ++ .oneline = "prints information about the current file", ++}; ++ ++static void discard_help(void) ++{ ++ printf( ++"\n" ++" discards a range of bytes from the given offset\n" ++"\n" ++" Example:\n" ++" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n" ++"\n" ++" Discards a segment of the currently open file.\n" ++" -C, -- report statistics in a machine parsable format\n" ++" -q, -- quiet mode, do not show I/O statistics\n" ++"\n"); ++} ++ ++static int discard_f(BlockDriverState *bs, int argc, char **argv); ++ ++static const cmdinfo_t discard_cmd = { ++ .name = "discard", ++ .altname = "d", ++ .cfunc = discard_f, ++ .argmin = 2, ++ .argmax = -1, ++ .args = "[-Cq] off len", ++ .oneline = "discards a number of bytes at a specified offset", ++ .help = discard_help, ++}; ++ ++static int discard_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ struct timeval t1, t2; ++ int Cflag = 0, qflag = 0; ++ int c, ret; ++ int64_t offset; ++ int count; ++ ++ while ((c = getopt(argc, argv, "Cq")) != EOF) { ++ switch (c) { ++ case 'C': ++ Cflag = 1; ++ break; ++ case 'q': ++ qflag = 1; ++ break; ++ default: ++ return command_usage(&discard_cmd); ++ } ++ } ++ ++ if (optind != argc - 2) { ++ return command_usage(&discard_cmd); ++ } ++ ++ offset = cvtnum(argv[optind]); ++ if (offset < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ return 0; ++ } ++ ++ optind++; ++ count = cvtnum(argv[optind]); ++ if (count < 0) { ++ printf("non-numeric length argument -- %s\n", argv[optind]); ++ return 0; ++ } ++ ++ gettimeofday(&t1, NULL); ++ ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS, ++ count >> BDRV_SECTOR_BITS); ++ gettimeofday(&t2, NULL); ++ ++ if (ret < 0) { ++ printf("discard failed: %s\n", strerror(-ret)); ++ goto out; ++ } ++ ++ /* Finally, report back -- -C gives a parsable format */ ++ if (!qflag) { ++ t2 = tsub(t2, t1); ++ print_report("discard", &t2, offset, count, count, 1, Cflag); ++ } ++ ++out: ++ return 0; ++} ++ ++static int alloc_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ int64_t offset, sector_num; ++ int nb_sectors, remaining; ++ char s1[64]; ++ int num, sum_alloc; ++ int ret; ++ ++ offset = cvtnum(argv[1]); ++ if (offset < 0) { ++ printf("non-numeric offset argument -- %s\n", argv[1]); ++ return 0; ++ } else if (offset & 0x1ff) { ++ printf("offset %" PRId64 " is not sector aligned\n", ++ offset); ++ return 0; ++ } ++ ++ if (argc == 3) { ++ nb_sectors = cvtnum(argv[2]); ++ if (nb_sectors < 0) { ++ printf("non-numeric length argument -- %s\n", argv[2]); ++ return 0; ++ } ++ } else { ++ nb_sectors = 1; ++ } ++ ++ remaining = nb_sectors; ++ sum_alloc = 0; ++ sector_num = offset >> 9; ++ while (remaining) { ++ ret = bdrv_is_allocated(bs, sector_num, remaining, &num); ++ if (ret < 0) { ++ printf("is_allocated failed: %s\n", strerror(-ret)); ++ return 0; ++ } ++ sector_num += num; ++ remaining -= num; ++ if (ret) { ++ sum_alloc += num; ++ } ++ if (num == 0) { ++ nb_sectors -= remaining; ++ remaining = 0; ++ } ++ } ++ ++ cvtstr(offset, s1, sizeof(s1)); ++ ++ printf("%d/%d sectors allocated at offset %s\n", ++ sum_alloc, nb_sectors, s1); ++ return 0; ++} ++ ++static const cmdinfo_t alloc_cmd = { ++ .name = "alloc", ++ .altname = "a", ++ .argmin = 1, ++ .argmax = 2, ++ .cfunc = alloc_f, ++ .args = "off [sectors]", ++ .oneline = "checks if a sector is present in the file", ++}; ++ ++static int map_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ int64_t offset; ++ int64_t nb_sectors; ++ char s1[64]; ++ int num, num_checked; ++ int ret; ++ const char *retstr; ++ ++ offset = 0; ++ nb_sectors = bs->total_sectors; ++ ++ do { ++ num_checked = MIN(nb_sectors, INT_MAX); ++ ret = bdrv_is_allocated(bs, offset, num_checked, &num); ++ retstr = ret ? " allocated" : "not allocated"; ++ cvtstr(offset << 9ULL, s1, sizeof(s1)); ++ printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n", ++ offset << 9ULL, num, num_checked, retstr, s1, ret); ++ ++ offset += num; ++ nb_sectors -= num; ++ } while (offset < bs->total_sectors); ++ ++ return 0; ++} ++ ++static const cmdinfo_t map_cmd = { ++ .name = "map", ++ .argmin = 0, ++ .argmax = 0, ++ .cfunc = map_f, ++ .args = "", ++ .oneline = "prints the allocated areas of a file", ++}; ++ ++static int break_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ int ret; ++ ++ ret = bdrv_debug_breakpoint(bs, argv[1], argv[2]); ++ if (ret < 0) { ++ printf("Could not set breakpoint: %s\n", strerror(-ret)); ++ } ++ ++ return 0; ++} ++ ++static const cmdinfo_t break_cmd = { ++ .name = "break", ++ .argmin = 2, ++ .argmax = 2, ++ .cfunc = break_f, ++ .args = "event tag", ++ .oneline = "sets a breakpoint on event and tags the stopped " ++ "request as tag", ++}; ++ ++static int resume_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ int ret; ++ ++ ret = bdrv_debug_resume(bs, argv[1]); ++ if (ret < 0) { ++ printf("Could not resume request: %s\n", strerror(-ret)); ++ } ++ ++ return 0; ++} ++ ++static const cmdinfo_t resume_cmd = { ++ .name = "resume", ++ .argmin = 1, ++ .argmax = 1, ++ .cfunc = resume_f, ++ .args = "tag", ++ .oneline = "resumes the request tagged as tag", ++}; ++ ++static int wait_break_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ while (!bdrv_debug_is_suspended(bs, argv[1])) { ++ qemu_aio_wait(); ++ } ++ ++ return 0; ++} ++ ++static const cmdinfo_t wait_break_cmd = { ++ .name = "wait_break", ++ .argmin = 1, ++ .argmax = 1, ++ .cfunc = wait_break_f, ++ .args = "tag", ++ .oneline = "waits for the suspension of a request", ++}; ++ ++static int abort_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ abort(); ++} ++ ++static const cmdinfo_t abort_cmd = { ++ .name = "abort", ++ .cfunc = abort_f, ++ .flags = CMD_NOFILE_OK, ++ .oneline = "simulate a program crash using abort(3)", ++}; ++ ++static void sleep_cb(void *opaque) ++{ ++ bool *expired = opaque; ++ *expired = true; ++} ++ ++static int sleep_f(BlockDriverState *bs, int argc, char **argv) ++{ ++ char *endptr; ++ long ms; ++ struct QEMUTimer *timer; ++ bool expired = false; ++ ++ ms = strtol(argv[1], &endptr, 0); ++ if (ms < 0 || *endptr != '\0') { ++ printf("%s is not a valid number\n", argv[1]); ++ return 0; ++ } ++ ++ timer = qemu_new_timer_ns(host_clock, sleep_cb, &expired); ++ qemu_mod_timer(timer, qemu_get_clock_ns(host_clock) + SCALE_MS * ms); ++ ++ while (!expired) { ++ main_loop_wait(false); ++ } ++ ++ qemu_free_timer(timer); ++ ++ return 0; ++} ++ ++static const cmdinfo_t sleep_cmd = { ++ .name = "sleep", ++ .argmin = 1, ++ .argmax = 1, ++ .cfunc = sleep_f, ++ .flags = CMD_NOFILE_OK, ++ .oneline = "waits for the given value in milliseconds", ++}; ++ ++ ++static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) ++{ ++ if (ct->flags & CMD_FLAG_GLOBAL) { ++ return 1; ++ } ++ if (!(ct->flags & CMD_NOFILE_OK) && !bs) { ++ fprintf(stderr, "no file open, try 'help open'\n"); ++ return 0; ++ } ++ return 1; ++} ++ ++static void __attribute((constructor)) init_qemuio_commands(void) ++{ ++ /* initialize commands */ ++ help_init(); ++ add_command(&read_cmd); ++ add_command(&readv_cmd); ++ add_command(&write_cmd); ++ add_command(&writev_cmd); ++ add_command(&multiwrite_cmd); ++ add_command(&aio_read_cmd); ++ add_command(&aio_write_cmd); ++ add_command(&aio_flush_cmd); ++ add_command(&flush_cmd); ++ add_command(&truncate_cmd); ++ add_command(&length_cmd); ++ add_command(&info_cmd); ++ add_command(&discard_cmd); ++ add_command(&alloc_cmd); ++ add_command(&map_cmd); ++ add_command(&break_cmd); ++ add_command(&resume_cmd); ++ add_command(&wait_break_cmd); ++ add_command(&abort_cmd); ++ add_command(&sleep_cmd); ++ ++ add_check_command(init_check_command); ++} +diff --git a/qemu-io.c b/qemu-io.c +index c3cc4f3..4f1c808 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -31,1761 +31,8 @@ + char *progname; + + BlockDriverState *qemuio_bs; +-static int misalign; + +-static int64_t cvtnum(const char *s) +-{ +- char *end; +- return strtosz_suffix(s, &end, STRTOSZ_DEFSUFFIX_B); +-} +- +-/* +- * Parse the pattern argument to various sub-commands. +- * +- * Because the pattern is used as an argument to memset it must evaluate +- * to an unsigned integer that fits into a single byte. +- */ +-static int parse_pattern(const char *arg) +-{ +- char *endptr = NULL; +- long pattern; +- +- pattern = strtol(arg, &endptr, 0); +- if (pattern < 0 || pattern > UCHAR_MAX || *endptr != '\0') { +- printf("%s is not a valid pattern byte\n", arg); +- return -1; +- } +- +- return pattern; +-} +- +-/* +- * Memory allocation helpers. +- * +- * Make sure memory is aligned by default, or purposefully misaligned if +- * that is specified on the command line. +- */ +- +-#define MISALIGN_OFFSET 16 +-static void *qemu_io_alloc(BlockDriverState *bs, size_t len, int pattern) +-{ +- void *buf; +- +- if (misalign) { +- len += MISALIGN_OFFSET; +- } +- buf = qemu_blockalign(bs, len); +- memset(buf, pattern, len); +- if (misalign) { +- buf += MISALIGN_OFFSET; +- } +- return buf; +-} +- +-static void qemu_io_free(void *p) +-{ +- if (misalign) { +- p -= MISALIGN_OFFSET; +- } +- qemu_vfree(p); +-} +- +-static void dump_buffer(const void *buffer, int64_t offset, int len) +-{ +- int i, j; +- const uint8_t *p; +- +- for (i = 0, p = buffer; i < len; i += 16) { +- const uint8_t *s = p; +- +- printf("%08" PRIx64 ": ", offset + i); +- for (j = 0; j < 16 && i + j < len; j++, p++) { +- printf("%02x ", *p); +- } +- printf(" "); +- for (j = 0; j < 16 && i + j < len; j++, s++) { +- if (isalnum(*s)) { +- printf("%c", *s); +- } else { +- printf("."); +- } +- } +- printf("\n"); +- } +-} +- +-static void print_report(const char *op, struct timeval *t, int64_t offset, +- int count, int total, int cnt, int Cflag) +-{ +- char s1[64], s2[64], ts[64]; +- +- timestr(t, ts, sizeof(ts), Cflag ? VERBOSE_FIXED_TIME : 0); +- if (!Cflag) { +- cvtstr((double)total, s1, sizeof(s1)); +- cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); +- printf("%s %d/%d bytes at offset %" PRId64 "\n", +- op, total, count, offset); +- printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", +- s1, cnt, ts, s2, tdiv((double)cnt, *t)); +- } else {/* bytes,ops,time,bytes/sec,ops/sec */ +- printf("%d,%d,%s,%.3f,%.3f\n", +- total, cnt, ts, +- tdiv((double)total, *t), +- tdiv((double)cnt, *t)); +- } +-} +- +-/* +- * Parse multiple length statements for vectored I/O, and construct an I/O +- * vector matching it. +- */ +-static void * +-create_iovec(BlockDriverState *bs, QEMUIOVector *qiov, char **argv, int nr_iov, +- int pattern) +-{ +- size_t *sizes = g_new0(size_t, nr_iov); +- size_t count = 0; +- void *buf = NULL; +- void *p; +- int i; +- +- for (i = 0; i < nr_iov; i++) { +- char *arg = argv[i]; +- int64_t len; +- +- len = cvtnum(arg); +- if (len < 0) { +- printf("non-numeric length argument -- %s\n", arg); +- goto fail; +- } +- +- /* should be SIZE_T_MAX, but that doesn't exist */ +- if (len > INT_MAX) { +- printf("too large length argument -- %s\n", arg); +- goto fail; +- } +- +- if (len & 0x1ff) { +- printf("length argument %" PRId64 +- " is not sector aligned\n", len); +- goto fail; +- } +- +- sizes[i] = len; +- count += len; +- } +- +- qemu_iovec_init(qiov, nr_iov); +- +- buf = p = qemu_io_alloc(bs, count, pattern); +- +- for (i = 0; i < nr_iov; i++) { +- qemu_iovec_add(qiov, p, sizes[i]); +- p += sizes[i]; +- } +- +-fail: +- g_free(sizes); +- return buf; +-} +- +-static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count, +- int *total) +-{ +- int ret; +- +- ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); +- if (ret < 0) { +- return ret; +- } +- *total = count; +- return 1; +-} +- +-static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count, +- int *total) +-{ +- int ret; +- +- ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); +- if (ret < 0) { +- return ret; +- } +- *total = count; +- return 1; +-} +- +-static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count, +- int *total) +-{ +- *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); +- if (*total < 0) { +- return *total; +- } +- return 1; +-} +- +-static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count, +- int *total) +-{ +- *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); +- if (*total < 0) { +- return *total; +- } +- return 1; +-} +- +-typedef struct { +- BlockDriverState *bs; +- int64_t offset; +- int count; +- int *total; +- int ret; +- bool done; +-} CoWriteZeroes; +- +-static void coroutine_fn co_write_zeroes_entry(void *opaque) +-{ +- CoWriteZeroes *data = opaque; +- +- data->ret = bdrv_co_write_zeroes(data->bs, data->offset / BDRV_SECTOR_SIZE, +- data->count / BDRV_SECTOR_SIZE, 0); +- data->done = true; +- if (data->ret < 0) { +- *data->total = data->ret; +- return; +- } +- +- *data->total = data->count; +-} +- +-static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, +- int *total) +-{ +- Coroutine *co; +- CoWriteZeroes data = { +- .bs = bs, +- .offset = offset, +- .count = count, +- .total = total, +- .done = false, +- }; +- +- co = qemu_coroutine_create(co_write_zeroes_entry); +- qemu_coroutine_enter(co, &data); +- while (!data.done) { +- qemu_aio_wait(); +- } +- if (data.ret < 0) { +- return data.ret; +- } else { +- return 1; +- } +-} +- +-static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset, +- int count, int *total) +-{ +- int ret; +- +- ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9); +- if (ret < 0) { +- return ret; +- } +- *total = count; +- return 1; +-} +- +-static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset, +- int count, int *total) +-{ +- *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); +- if (*total < 0) { +- return *total; +- } +- return 1; +-} +- +-static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset, +- int count, int *total) +-{ +- *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); +- if (*total < 0) { +- return *total; +- } +- return 1; +-} +- +-#define NOT_DONE 0x7fffffff +-static void aio_rw_done(void *opaque, int ret) +-{ +- *(int *)opaque = ret; +-} +- +-static int do_aio_readv(BlockDriverState *bs, QEMUIOVector *qiov, +- int64_t offset, int *total) +-{ +- int async_ret = NOT_DONE; +- +- bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9, +- aio_rw_done, &async_ret); +- while (async_ret == NOT_DONE) { +- main_loop_wait(false); +- } +- +- *total = qiov->size; +- return async_ret < 0 ? async_ret : 1; +-} +- +-static int do_aio_writev(BlockDriverState *bs, QEMUIOVector *qiov, +- int64_t offset, int *total) +-{ +- int async_ret = NOT_DONE; +- +- bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9, +- aio_rw_done, &async_ret); +- while (async_ret == NOT_DONE) { +- main_loop_wait(false); +- } +- +- *total = qiov->size; +- return async_ret < 0 ? async_ret : 1; +-} +- +-struct multiwrite_async_ret { +- int num_done; +- int error; +-}; +- +-static void multiwrite_cb(void *opaque, int ret) +-{ +- struct multiwrite_async_ret *async_ret = opaque; +- +- async_ret->num_done++; +- if (ret < 0) { +- async_ret->error = ret; +- } +-} +- +-static int do_aio_multiwrite(BlockDriverState *bs, BlockRequest* reqs, +- int num_reqs, int *total) +-{ +- int i, ret; +- struct multiwrite_async_ret async_ret = { +- .num_done = 0, +- .error = 0, +- }; +- +- *total = 0; +- for (i = 0; i < num_reqs; i++) { +- reqs[i].cb = multiwrite_cb; +- reqs[i].opaque = &async_ret; +- *total += reqs[i].qiov->size; +- } +- +- ret = bdrv_aio_multiwrite(bs, reqs, num_reqs); +- if (ret < 0) { +- return ret; +- } +- +- while (async_ret.num_done < num_reqs) { +- main_loop_wait(false); +- } +- +- return async_ret.error < 0 ? async_ret.error : 1; +-} +- +-static void read_help(void) +-{ +- printf( +-"\n" +-" reads a range of bytes from the given offset\n" +-"\n" +-" Example:\n" +-" 'read -v 512 1k' - dumps 1 kilobyte read from 512 bytes into the file\n" +-"\n" +-" Reads a segment of the currently open file, optionally dumping it to the\n" +-" standard output stream (with -v option) for subsequent inspection.\n" +-" -b, -- read from the VM state rather than the virtual disk\n" +-" -C, -- report statistics in a machine parsable format\n" +-" -l, -- length for pattern verification (only with -P)\n" +-" -p, -- use bdrv_pread to read the file\n" +-" -P, -- use a pattern to verify read data\n" +-" -q, -- quiet mode, do not show I/O statistics\n" +-" -s, -- start offset for pattern verification (only with -P)\n" +-" -v, -- dump buffer to standard output\n" +-"\n"); +-} +- +-static int read_f(BlockDriverState *bs, int argc, char **argv); +- +-static const cmdinfo_t read_cmd = { +- .name = "read", +- .altname = "r", +- .cfunc = read_f, +- .argmin = 2, +- .argmax = -1, +- .args = "[-abCpqv] [-P pattern [-s off] [-l len]] off len", +- .oneline = "reads a number of bytes at a specified offset", +- .help = read_help, +-}; +- +-static int read_f(BlockDriverState *bs, int argc, char **argv) +-{ +- struct timeval t1, t2; +- int Cflag = 0, pflag = 0, qflag = 0, vflag = 0; +- int Pflag = 0, sflag = 0, lflag = 0, bflag = 0; +- int c, cnt; +- char *buf; +- int64_t offset; +- int count; +- /* Some compilers get confused and warn if this is not initialized. */ +- int total = 0; +- int pattern = 0, pattern_offset = 0, pattern_count = 0; +- +- while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) { +- switch (c) { +- case 'b': +- bflag = 1; +- break; +- case 'C': +- Cflag = 1; +- break; +- case 'l': +- lflag = 1; +- pattern_count = cvtnum(optarg); +- if (pattern_count < 0) { +- printf("non-numeric length argument -- %s\n", optarg); +- return 0; +- } +- break; +- case 'p': +- pflag = 1; +- break; +- case 'P': +- Pflag = 1; +- pattern = parse_pattern(optarg); +- if (pattern < 0) { +- return 0; +- } +- break; +- case 'q': +- qflag = 1; +- break; +- case 's': +- sflag = 1; +- pattern_offset = cvtnum(optarg); +- if (pattern_offset < 0) { +- printf("non-numeric length argument -- %s\n", optarg); +- return 0; +- } +- break; +- case 'v': +- vflag = 1; +- break; +- default: +- return command_usage(&read_cmd); +- } +- } +- +- if (optind != argc - 2) { +- return command_usage(&read_cmd); +- } +- +- if (bflag && pflag) { +- printf("-b and -p cannot be specified at the same time\n"); +- return 0; +- } +- +- offset = cvtnum(argv[optind]); +- if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- return 0; +- } +- +- optind++; +- count = cvtnum(argv[optind]); +- if (count < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- return 0; +- } +- +- if (!Pflag && (lflag || sflag)) { +- return command_usage(&read_cmd); +- } +- +- if (!lflag) { +- pattern_count = count - pattern_offset; +- } +- +- if ((pattern_count < 0) || (pattern_count + pattern_offset > count)) { +- printf("pattern verification range exceeds end of read data\n"); +- return 0; +- } +- +- if (!pflag) { +- if (offset & 0x1ff) { +- printf("offset %" PRId64 " is not sector aligned\n", +- offset); +- return 0; +- } +- if (count & 0x1ff) { +- printf("count %d is not sector aligned\n", +- count); +- return 0; +- } +- } +- +- buf = qemu_io_alloc(bs, count, 0xab); +- +- gettimeofday(&t1, NULL); +- if (pflag) { +- cnt = do_pread(bs, buf, offset, count, &total); +- } else if (bflag) { +- cnt = do_load_vmstate(bs, buf, offset, count, &total); +- } else { +- cnt = do_read(bs, buf, offset, count, &total); +- } +- gettimeofday(&t2, NULL); +- +- if (cnt < 0) { +- printf("read failed: %s\n", strerror(-cnt)); +- goto out; +- } +- +- if (Pflag) { +- void *cmp_buf = g_malloc(pattern_count); +- memset(cmp_buf, pattern, pattern_count); +- if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { +- printf("Pattern verification failed at offset %" +- PRId64 ", %d bytes\n", +- offset + pattern_offset, pattern_count); +- } +- g_free(cmp_buf); +- } +- +- if (qflag) { +- goto out; +- } +- +- if (vflag) { +- dump_buffer(buf, offset, count); +- } +- +- /* Finally, report back -- -C gives a parsable format */ +- t2 = tsub(t2, t1); +- print_report("read", &t2, offset, count, total, cnt, Cflag); +- +-out: +- qemu_io_free(buf); +- +- return 0; +-} +- +-static void readv_help(void) +-{ +- printf( +-"\n" +-" reads a range of bytes from the given offset into multiple buffers\n" +-"\n" +-" Example:\n" +-" 'readv -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" +-"\n" +-" Reads a segment of the currently open file, optionally dumping it to the\n" +-" standard output stream (with -v option) for subsequent inspection.\n" +-" Uses multiple iovec buffers if more than one byte range is specified.\n" +-" -C, -- report statistics in a machine parsable format\n" +-" -P, -- use a pattern to verify read data\n" +-" -v, -- dump buffer to standard output\n" +-" -q, -- quiet mode, do not show I/O statistics\n" +-"\n"); +-} +- +-static int readv_f(BlockDriverState *bs, int argc, char **argv); +- +-static const cmdinfo_t readv_cmd = { +- .name = "readv", +- .cfunc = readv_f, +- .argmin = 2, +- .argmax = -1, +- .args = "[-Cqv] [-P pattern ] off len [len..]", +- .oneline = "reads a number of bytes at a specified offset", +- .help = readv_help, +-}; +- +-static int readv_f(BlockDriverState *bs, int argc, char **argv) +-{ +- struct timeval t1, t2; +- int Cflag = 0, qflag = 0, vflag = 0; +- int c, cnt; +- char *buf; +- int64_t offset; +- /* Some compilers get confused and warn if this is not initialized. */ +- int total = 0; +- int nr_iov; +- QEMUIOVector qiov; +- int pattern = 0; +- int Pflag = 0; +- +- while ((c = getopt(argc, argv, "CP:qv")) != EOF) { +- switch (c) { +- case 'C': +- Cflag = 1; +- break; +- case 'P': +- Pflag = 1; +- pattern = parse_pattern(optarg); +- if (pattern < 0) { +- return 0; +- } +- break; +- case 'q': +- qflag = 1; +- break; +- case 'v': +- vflag = 1; +- break; +- default: +- return command_usage(&readv_cmd); +- } +- } +- +- if (optind > argc - 2) { +- return command_usage(&readv_cmd); +- } +- +- +- offset = cvtnum(argv[optind]); +- if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- return 0; +- } +- optind++; +- +- if (offset & 0x1ff) { +- printf("offset %" PRId64 " is not sector aligned\n", +- offset); +- return 0; +- } +- +- nr_iov = argc - optind; +- buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, 0xab); +- if (buf == NULL) { +- return 0; +- } +- +- gettimeofday(&t1, NULL); +- cnt = do_aio_readv(bs, &qiov, offset, &total); +- gettimeofday(&t2, NULL); +- +- if (cnt < 0) { +- printf("readv failed: %s\n", strerror(-cnt)); +- goto out; +- } +- +- if (Pflag) { +- void *cmp_buf = g_malloc(qiov.size); +- memset(cmp_buf, pattern, qiov.size); +- if (memcmp(buf, cmp_buf, qiov.size)) { +- printf("Pattern verification failed at offset %" +- PRId64 ", %zd bytes\n", offset, qiov.size); +- } +- g_free(cmp_buf); +- } +- +- if (qflag) { +- goto out; +- } +- +- if (vflag) { +- dump_buffer(buf, offset, qiov.size); +- } +- +- /* Finally, report back -- -C gives a parsable format */ +- t2 = tsub(t2, t1); +- print_report("read", &t2, offset, qiov.size, total, cnt, Cflag); +- +-out: +- qemu_iovec_destroy(&qiov); +- qemu_io_free(buf); +- return 0; +-} +- +-static void write_help(void) +-{ +- printf( +-"\n" +-" writes a range of bytes from the given offset\n" +-"\n" +-" Example:\n" +-" 'write 512 1k' - writes 1 kilobyte at 512 bytes into the open file\n" +-"\n" +-" Writes into a segment of the currently open file, using a buffer\n" +-" filled with a set pattern (0xcdcdcdcd).\n" +-" -b, -- write to the VM state rather than the virtual disk\n" +-" -c, -- write compressed data with bdrv_write_compressed\n" +-" -p, -- use bdrv_pwrite to write the file\n" +-" -P, -- use different pattern to fill file\n" +-" -C, -- report statistics in a machine parsable format\n" +-" -q, -- quiet mode, do not show I/O statistics\n" +-" -z, -- write zeroes using bdrv_co_write_zeroes\n" +-"\n"); +-} +- +-static int write_f(BlockDriverState *bs, int argc, char **argv); +- +-static const cmdinfo_t write_cmd = { +- .name = "write", +- .altname = "w", +- .cfunc = write_f, +- .argmin = 2, +- .argmax = -1, +- .args = "[-bcCpqz] [-P pattern ] off len", +- .oneline = "writes a number of bytes at a specified offset", +- .help = write_help, +-}; +- +-static int write_f(BlockDriverState *bs, int argc, char **argv) +-{ +- struct timeval t1, t2; +- int Cflag = 0, pflag = 0, qflag = 0, bflag = 0, Pflag = 0, zflag = 0; +- int cflag = 0; +- int c, cnt; +- char *buf = NULL; +- int64_t offset; +- int count; +- /* Some compilers get confused and warn if this is not initialized. */ +- int total = 0; +- int pattern = 0xcd; +- +- while ((c = getopt(argc, argv, "bcCpP:qz")) != EOF) { +- switch (c) { +- case 'b': +- bflag = 1; +- break; +- case 'c': +- cflag = 1; +- break; +- case 'C': +- Cflag = 1; +- break; +- case 'p': +- pflag = 1; +- break; +- case 'P': +- Pflag = 1; +- pattern = parse_pattern(optarg); +- if (pattern < 0) { +- return 0; +- } +- break; +- case 'q': +- qflag = 1; +- break; +- case 'z': +- zflag = 1; +- break; +- default: +- return command_usage(&write_cmd); +- } +- } +- +- if (optind != argc - 2) { +- return command_usage(&write_cmd); +- } +- +- if (bflag + pflag + zflag > 1) { +- printf("-b, -p, or -z cannot be specified at the same time\n"); +- return 0; +- } +- +- if (zflag && Pflag) { +- printf("-z and -P cannot be specified at the same time\n"); +- return 0; +- } +- +- offset = cvtnum(argv[optind]); +- if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- return 0; +- } +- +- optind++; +- count = cvtnum(argv[optind]); +- if (count < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- return 0; +- } +- +- if (!pflag) { +- if (offset & 0x1ff) { +- printf("offset %" PRId64 " is not sector aligned\n", +- offset); +- return 0; +- } +- +- if (count & 0x1ff) { +- printf("count %d is not sector aligned\n", +- count); +- return 0; +- } +- } +- +- if (!zflag) { +- buf = qemu_io_alloc(bs, count, pattern); +- } +- +- gettimeofday(&t1, NULL); +- if (pflag) { +- cnt = do_pwrite(bs, buf, offset, count, &total); +- } else if (bflag) { +- cnt = do_save_vmstate(bs, buf, offset, count, &total); +- } else if (zflag) { +- cnt = do_co_write_zeroes(bs, offset, count, &total); +- } else if (cflag) { +- cnt = do_write_compressed(bs, buf, offset, count, &total); +- } else { +- cnt = do_write(bs, buf, offset, count, &total); +- } +- gettimeofday(&t2, NULL); +- +- if (cnt < 0) { +- printf("write failed: %s\n", strerror(-cnt)); +- goto out; +- } +- +- if (qflag) { +- goto out; +- } +- +- /* Finally, report back -- -C gives a parsable format */ +- t2 = tsub(t2, t1); +- print_report("wrote", &t2, offset, count, total, cnt, Cflag); +- +-out: +- if (!zflag) { +- qemu_io_free(buf); +- } +- +- return 0; +-} +- +-static void +-writev_help(void) +-{ +- printf( +-"\n" +-" writes a range of bytes from the given offset source from multiple buffers\n" +-"\n" +-" Example:\n" +-" 'write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" +-"\n" +-" Writes into a segment of the currently open file, using a buffer\n" +-" filled with a set pattern (0xcdcdcdcd).\n" +-" -P, -- use different pattern to fill file\n" +-" -C, -- report statistics in a machine parsable format\n" +-" -q, -- quiet mode, do not show I/O statistics\n" +-"\n"); +-} +- +-static int writev_f(BlockDriverState *bs, int argc, char **argv); +- +-static const cmdinfo_t writev_cmd = { +- .name = "writev", +- .cfunc = writev_f, +- .argmin = 2, +- .argmax = -1, +- .args = "[-Cq] [-P pattern ] off len [len..]", +- .oneline = "writes a number of bytes at a specified offset", +- .help = writev_help, +-}; +- +-static int writev_f(BlockDriverState *bs, int argc, char **argv) +-{ +- struct timeval t1, t2; +- int Cflag = 0, qflag = 0; +- int c, cnt; +- char *buf; +- int64_t offset; +- /* Some compilers get confused and warn if this is not initialized. */ +- int total = 0; +- int nr_iov; +- int pattern = 0xcd; +- QEMUIOVector qiov; +- +- while ((c = getopt(argc, argv, "CqP:")) != EOF) { +- switch (c) { +- case 'C': +- Cflag = 1; +- break; +- case 'q': +- qflag = 1; +- break; +- case 'P': +- pattern = parse_pattern(optarg); +- if (pattern < 0) { +- return 0; +- } +- break; +- default: +- return command_usage(&writev_cmd); +- } +- } +- +- if (optind > argc - 2) { +- return command_usage(&writev_cmd); +- } +- +- offset = cvtnum(argv[optind]); +- if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- return 0; +- } +- optind++; +- +- if (offset & 0x1ff) { +- printf("offset %" PRId64 " is not sector aligned\n", +- offset); +- return 0; +- } +- +- nr_iov = argc - optind; +- buf = create_iovec(bs, &qiov, &argv[optind], nr_iov, pattern); +- if (buf == NULL) { +- return 0; +- } +- +- gettimeofday(&t1, NULL); +- cnt = do_aio_writev(bs, &qiov, offset, &total); +- gettimeofday(&t2, NULL); +- +- if (cnt < 0) { +- printf("writev failed: %s\n", strerror(-cnt)); +- goto out; +- } +- +- if (qflag) { +- goto out; +- } +- +- /* Finally, report back -- -C gives a parsable format */ +- t2 = tsub(t2, t1); +- print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag); +-out: +- qemu_iovec_destroy(&qiov); +- qemu_io_free(buf); +- return 0; +-} +- +-static void multiwrite_help(void) +-{ +- printf( +-"\n" +-" writes a range of bytes from the given offset source from multiple buffers,\n" +-" in a batch of requests that may be merged by qemu\n" +-"\n" +-" Example:\n" +-" 'multiwrite 512 1k 1k ; 4k 1k'\n" +-" writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n" +-"\n" +-" Writes into a segment of the currently open file, using a buffer\n" +-" filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n" +-" by one for each request contained in the multiwrite command.\n" +-" -P, -- use different pattern to fill file\n" +-" -C, -- report statistics in a machine parsable format\n" +-" -q, -- quiet mode, do not show I/O statistics\n" +-"\n"); +-} +- +-static int multiwrite_f(BlockDriverState *bs, int argc, char **argv); +- +-static const cmdinfo_t multiwrite_cmd = { +- .name = "multiwrite", +- .cfunc = multiwrite_f, +- .argmin = 2, +- .argmax = -1, +- .args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]", +- .oneline = "issues multiple write requests at once", +- .help = multiwrite_help, +-}; +- +-static int multiwrite_f(BlockDriverState *bs, int argc, char **argv) +-{ +- struct timeval t1, t2; +- int Cflag = 0, qflag = 0; +- int c, cnt; +- char **buf; +- int64_t offset, first_offset = 0; +- /* Some compilers get confused and warn if this is not initialized. */ +- int total = 0; +- int nr_iov; +- int nr_reqs; +- int pattern = 0xcd; +- QEMUIOVector *qiovs; +- int i; +- BlockRequest *reqs; +- +- while ((c = getopt(argc, argv, "CqP:")) != EOF) { +- switch (c) { +- case 'C': +- Cflag = 1; +- break; +- case 'q': +- qflag = 1; +- break; +- case 'P': +- pattern = parse_pattern(optarg); +- if (pattern < 0) { +- return 0; +- } +- break; +- default: +- return command_usage(&writev_cmd); +- } +- } +- +- if (optind > argc - 2) { +- return command_usage(&writev_cmd); +- } +- +- nr_reqs = 1; +- for (i = optind; i < argc; i++) { +- if (!strcmp(argv[i], ";")) { +- nr_reqs++; +- } +- } +- +- reqs = g_malloc0(nr_reqs * sizeof(*reqs)); +- buf = g_malloc0(nr_reqs * sizeof(*buf)); +- qiovs = g_malloc(nr_reqs * sizeof(*qiovs)); +- +- for (i = 0; i < nr_reqs && optind < argc; i++) { +- int j; +- +- /* Read the offset of the request */ +- offset = cvtnum(argv[optind]); +- if (offset < 0) { +- printf("non-numeric offset argument -- %s\n", argv[optind]); +- goto out; +- } +- optind++; +- +- if (offset & 0x1ff) { +- printf("offset %lld is not sector aligned\n", +- (long long)offset); +- goto out; +- } +- +- if (i == 0) { +- first_offset = offset; +- } +- +- /* Read lengths for qiov entries */ +- for (j = optind; j < argc; j++) { +- if (!strcmp(argv[j], ";")) { +- break; +- } +- } +- +- nr_iov = j - optind; +- +- /* Build request */ +- buf[i] = create_iovec(bs, &qiovs[i], &argv[optind], nr_iov, pattern); +- if (buf[i] == NULL) { +- goto out; +- } +- +- reqs[i].qiov = &qiovs[i]; +- reqs[i].sector = offset >> 9; +- reqs[i].nb_sectors = reqs[i].qiov->size >> 9; +- +- optind = j + 1; +- +- pattern++; +- } +- +- /* If there were empty requests at the end, ignore them */ +- nr_reqs = i; +- +- gettimeofday(&t1, NULL); +- cnt = do_aio_multiwrite(bs, reqs, nr_reqs, &total); +- gettimeofday(&t2, NULL); +- +- if (cnt < 0) { +- printf("aio_multiwrite failed: %s\n", strerror(-cnt)); +- goto out; +- } +- +- if (qflag) { +- goto out; +- } +- +- /* Finally, report back -- -C gives a parsable format */ +- t2 = tsub(t2, t1); +- print_report("wrote", &t2, first_offset, total, total, cnt, Cflag); +-out: +- for (i = 0; i < nr_reqs; i++) { +- qemu_io_free(buf[i]); +- if (reqs[i].qiov != NULL) { +- qemu_iovec_destroy(&qiovs[i]); +- } +- } +- g_free(buf); +- g_free(reqs); +- g_free(qiovs); +- return 0; +-} +- +-struct aio_ctx { +- QEMUIOVector qiov; +- int64_t offset; +- char *buf; +- int qflag; +- int vflag; +- int Cflag; +- int Pflag; +- int pattern; +- struct timeval t1; +-}; +- +-static void aio_write_done(void *opaque, int ret) +-{ +- struct aio_ctx *ctx = opaque; +- struct timeval t2; +- +- gettimeofday(&t2, NULL); +- +- +- if (ret < 0) { +- printf("aio_write failed: %s\n", strerror(-ret)); +- goto out; +- } +- +- if (ctx->qflag) { +- goto out; +- } +- +- /* Finally, report back -- -C gives a parsable format */ +- t2 = tsub(t2, ctx->t1); +- print_report("wrote", &t2, ctx->offset, ctx->qiov.size, +- ctx->qiov.size, 1, ctx->Cflag); +-out: +- qemu_io_free(ctx->buf); +- qemu_iovec_destroy(&ctx->qiov); +- g_free(ctx); +-} +- +-static void aio_read_done(void *opaque, int ret) +-{ +- struct aio_ctx *ctx = opaque; +- struct timeval t2; +- +- gettimeofday(&t2, NULL); +- +- if (ret < 0) { +- printf("readv failed: %s\n", strerror(-ret)); +- goto out; +- } +- +- if (ctx->Pflag) { +- void *cmp_buf = g_malloc(ctx->qiov.size); +- +- memset(cmp_buf, ctx->pattern, ctx->qiov.size); +- if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) { +- printf("Pattern verification failed at offset %" +- PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size); +- } +- g_free(cmp_buf); +- } +- +- if (ctx->qflag) { +- goto out; +- } +- +- if (ctx->vflag) { +- dump_buffer(ctx->buf, ctx->offset, ctx->qiov.size); +- } +- +- /* Finally, report back -- -C gives a parsable format */ +- t2 = tsub(t2, ctx->t1); +- print_report("read", &t2, ctx->offset, ctx->qiov.size, +- ctx->qiov.size, 1, ctx->Cflag); +-out: +- qemu_io_free(ctx->buf); +- qemu_iovec_destroy(&ctx->qiov); +- g_free(ctx); +-} +- +-static void aio_read_help(void) +-{ +- printf( +-"\n" +-" asynchronously reads a range of bytes from the given offset\n" +-"\n" +-" Example:\n" +-" 'aio_read -v 512 1k 1k ' - dumps 2 kilobytes read from 512 bytes into the file\n" +-"\n" +-" Reads a segment of the currently open file, optionally dumping it to the\n" +-" standard output stream (with -v option) for subsequent inspection.\n" +-" The read is performed asynchronously and the aio_flush command must be\n" +-" used to ensure all outstanding aio requests have been completed.\n" +-" -C, -- report statistics in a machine parsable format\n" +-" -P, -- use a pattern to verify read data\n" +-" -v, -- dump buffer to standard output\n" +-" -q, -- quiet mode, do not show I/O statistics\n" +-"\n"); +-} +- +-static int aio_read_f(BlockDriverState *bs, int argc, char **argv); +- +-static const cmdinfo_t aio_read_cmd = { +- .name = "aio_read", +- .cfunc = aio_read_f, +- .argmin = 2, +- .argmax = -1, +- .args = "[-Cqv] [-P pattern ] off len [len..]", +- .oneline = "asynchronously reads a number of bytes", +- .help = aio_read_help, +-}; +- +-static int aio_read_f(BlockDriverState *bs, int argc, char **argv) +-{ +- int nr_iov, c; +- struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); +- +- while ((c = getopt(argc, argv, "CP:qv")) != EOF) { +- switch (c) { +- case 'C': +- ctx->Cflag = 1; +- break; +- case 'P': +- ctx->Pflag = 1; +- ctx->pattern = parse_pattern(optarg); +- if (ctx->pattern < 0) { +- g_free(ctx); +- return 0; +- } +- break; +- case 'q': +- ctx->qflag = 1; +- break; +- case 'v': +- ctx->vflag = 1; +- break; +- default: +- g_free(ctx); +- return command_usage(&aio_read_cmd); +- } +- } +- +- if (optind > argc - 2) { +- g_free(ctx); +- return command_usage(&aio_read_cmd); +- } +- +- ctx->offset = cvtnum(argv[optind]); +- if (ctx->offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- g_free(ctx); +- return 0; +- } +- optind++; +- +- if (ctx->offset & 0x1ff) { +- printf("offset %" PRId64 " is not sector aligned\n", +- ctx->offset); +- g_free(ctx); +- return 0; +- } +- +- nr_iov = argc - optind; +- ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, 0xab); +- if (ctx->buf == NULL) { +- g_free(ctx); +- return 0; +- } +- +- gettimeofday(&ctx->t1, NULL); +- bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, +- ctx->qiov.size >> 9, aio_read_done, ctx); +- return 0; +-} +- +-static void aio_write_help(void) +-{ +- printf( +-"\n" +-" asynchronously writes a range of bytes from the given offset source\n" +-" from multiple buffers\n" +-"\n" +-" Example:\n" +-" 'aio_write 512 1k 1k' - writes 2 kilobytes at 512 bytes into the open file\n" +-"\n" +-" Writes into a segment of the currently open file, using a buffer\n" +-" filled with a set pattern (0xcdcdcdcd).\n" +-" The write is performed asynchronously and the aio_flush command must be\n" +-" used to ensure all outstanding aio requests have been completed.\n" +-" -P, -- use different pattern to fill file\n" +-" -C, -- report statistics in a machine parsable format\n" +-" -q, -- quiet mode, do not show I/O statistics\n" +-"\n"); +-} +- +-static int aio_write_f(BlockDriverState *bs, int argc, char **argv); +- +-static const cmdinfo_t aio_write_cmd = { +- .name = "aio_write", +- .cfunc = aio_write_f, +- .argmin = 2, +- .argmax = -1, +- .args = "[-Cq] [-P pattern ] off len [len..]", +- .oneline = "asynchronously writes a number of bytes", +- .help = aio_write_help, +-}; +- +-static int aio_write_f(BlockDriverState *bs, int argc, char **argv) +-{ +- int nr_iov, c; +- int pattern = 0xcd; +- struct aio_ctx *ctx = g_new0(struct aio_ctx, 1); +- +- while ((c = getopt(argc, argv, "CqP:")) != EOF) { +- switch (c) { +- case 'C': +- ctx->Cflag = 1; +- break; +- case 'q': +- ctx->qflag = 1; +- break; +- case 'P': +- pattern = parse_pattern(optarg); +- if (pattern < 0) { +- g_free(ctx); +- return 0; +- } +- break; +- default: +- g_free(ctx); +- return command_usage(&aio_write_cmd); +- } +- } +- +- if (optind > argc - 2) { +- g_free(ctx); +- return command_usage(&aio_write_cmd); +- } +- +- ctx->offset = cvtnum(argv[optind]); +- if (ctx->offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- g_free(ctx); +- return 0; +- } +- optind++; +- +- if (ctx->offset & 0x1ff) { +- printf("offset %" PRId64 " is not sector aligned\n", +- ctx->offset); +- g_free(ctx); +- return 0; +- } +- +- nr_iov = argc - optind; +- ctx->buf = create_iovec(bs, &ctx->qiov, &argv[optind], nr_iov, pattern); +- if (ctx->buf == NULL) { +- g_free(ctx); +- return 0; +- } +- +- gettimeofday(&ctx->t1, NULL); +- bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, +- ctx->qiov.size >> 9, aio_write_done, ctx); +- return 0; +-} +- +-static int aio_flush_f(BlockDriverState *bs, int argc, char **argv) +-{ +- bdrv_drain_all(); +- return 0; +-} +- +-static const cmdinfo_t aio_flush_cmd = { +- .name = "aio_flush", +- .cfunc = aio_flush_f, +- .oneline = "completes all outstanding aio requests" +-}; +- +-static int flush_f(BlockDriverState *bs, int argc, char **argv) +-{ +- bdrv_flush(bs); +- return 0; +-} +- +-static const cmdinfo_t flush_cmd = { +- .name = "flush", +- .altname = "f", +- .cfunc = flush_f, +- .oneline = "flush all in-core file state to disk", +-}; +- +-static int truncate_f(BlockDriverState *bs, int argc, char **argv) +-{ +- int64_t offset; +- int ret; +- +- offset = cvtnum(argv[1]); +- if (offset < 0) { +- printf("non-numeric truncate argument -- %s\n", argv[1]); +- return 0; +- } +- +- ret = bdrv_truncate(bs, offset); +- if (ret < 0) { +- printf("truncate: %s\n", strerror(-ret)); +- return 0; +- } +- +- return 0; +-} +- +-static const cmdinfo_t truncate_cmd = { +- .name = "truncate", +- .altname = "t", +- .cfunc = truncate_f, +- .argmin = 1, +- .argmax = 1, +- .args = "off", +- .oneline = "truncates the current file at the given offset", +-}; +- +-static int length_f(BlockDriverState *bs, int argc, char **argv) +-{ +- int64_t size; +- char s1[64]; +- +- size = bdrv_getlength(bs); +- if (size < 0) { +- printf("getlength: %s\n", strerror(-size)); +- return 0; +- } +- +- cvtstr(size, s1, sizeof(s1)); +- printf("%s\n", s1); +- return 0; +-} +- +- +-static const cmdinfo_t length_cmd = { +- .name = "length", +- .altname = "l", +- .cfunc = length_f, +- .oneline = "gets the length of the current file", +-}; +- +- +-static int info_f(BlockDriverState *bs, int argc, char **argv) +-{ +- BlockDriverInfo bdi; +- ImageInfoSpecific *spec_info; +- char s1[64], s2[64]; +- int ret; +- +- if (bs->drv && bs->drv->format_name) { +- printf("format name: %s\n", bs->drv->format_name); +- } +- if (bs->drv && bs->drv->protocol_name) { +- printf("format name: %s\n", bs->drv->protocol_name); +- } +- +- ret = bdrv_get_info(bs, &bdi); +- if (ret) { +- return 0; +- } +- +- cvtstr(bdi.cluster_size, s1, sizeof(s1)); +- cvtstr(bdi.vm_state_offset, s2, sizeof(s2)); +- +- printf("cluster size: %s\n", s1); +- printf("vm state offset: %s\n", s2); +- +- spec_info = bdrv_get_specific_info(bs); +- if (spec_info) { +- printf("Format specific information:\n"); +- bdrv_image_info_specific_dump(fprintf, stdout, spec_info); +- qapi_free_ImageInfoSpecific(spec_info); +- } +- +- return 0; +-} +- +- +- +-static const cmdinfo_t info_cmd = { +- .name = "info", +- .altname = "i", +- .cfunc = info_f, +- .oneline = "prints information about the current file", +-}; +- +-static void discard_help(void) +-{ +- printf( +-"\n" +-" discards a range of bytes from the given offset\n" +-"\n" +-" Example:\n" +-" 'discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n" +-"\n" +-" Discards a segment of the currently open file.\n" +-" -C, -- report statistics in a machine parsable format\n" +-" -q, -- quiet mode, do not show I/O statistics\n" +-"\n"); +-} +- +-static int discard_f(BlockDriverState *bs, int argc, char **argv); +- +-static const cmdinfo_t discard_cmd = { +- .name = "discard", +- .altname = "d", +- .cfunc = discard_f, +- .argmin = 2, +- .argmax = -1, +- .args = "[-Cq] off len", +- .oneline = "discards a number of bytes at a specified offset", +- .help = discard_help, +-}; +- +-static int discard_f(BlockDriverState *bs, int argc, char **argv) +-{ +- struct timeval t1, t2; +- int Cflag = 0, qflag = 0; +- int c, ret; +- int64_t offset; +- int count; +- +- while ((c = getopt(argc, argv, "Cq")) != EOF) { +- switch (c) { +- case 'C': +- Cflag = 1; +- break; +- case 'q': +- qflag = 1; +- break; +- default: +- return command_usage(&discard_cmd); +- } +- } +- +- if (optind != argc - 2) { +- return command_usage(&discard_cmd); +- } +- +- offset = cvtnum(argv[optind]); +- if (offset < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- return 0; +- } +- +- optind++; +- count = cvtnum(argv[optind]); +- if (count < 0) { +- printf("non-numeric length argument -- %s\n", argv[optind]); +- return 0; +- } +- +- gettimeofday(&t1, NULL); +- ret = bdrv_discard(bs, offset >> BDRV_SECTOR_BITS, +- count >> BDRV_SECTOR_BITS); +- gettimeofday(&t2, NULL); +- +- if (ret < 0) { +- printf("discard failed: %s\n", strerror(-ret)); +- goto out; +- } +- +- /* Finally, report back -- -C gives a parsable format */ +- if (!qflag) { +- t2 = tsub(t2, t1); +- print_report("discard", &t2, offset, count, count, 1, Cflag); +- } +- +-out: +- return 0; +-} +- +-static int alloc_f(BlockDriverState *bs, int argc, char **argv) +-{ +- int64_t offset, sector_num; +- int nb_sectors, remaining; +- char s1[64]; +- int num, sum_alloc; +- int ret; +- +- offset = cvtnum(argv[1]); +- if (offset < 0) { +- printf("non-numeric offset argument -- %s\n", argv[1]); +- return 0; +- } else if (offset & 0x1ff) { +- printf("offset %" PRId64 " is not sector aligned\n", +- offset); +- return 0; +- } +- +- if (argc == 3) { +- nb_sectors = cvtnum(argv[2]); +- if (nb_sectors < 0) { +- printf("non-numeric length argument -- %s\n", argv[2]); +- return 0; +- } +- } else { +- nb_sectors = 1; +- } +- +- remaining = nb_sectors; +- sum_alloc = 0; +- sector_num = offset >> 9; +- while (remaining) { +- ret = bdrv_is_allocated(bs, sector_num, remaining, &num); +- if (ret < 0) { +- printf("is_allocated failed: %s\n", strerror(-ret)); +- return 0; +- } +- sector_num += num; +- remaining -= num; +- if (ret) { +- sum_alloc += num; +- } +- if (num == 0) { +- nb_sectors -= remaining; +- remaining = 0; +- } +- } +- +- cvtstr(offset, s1, sizeof(s1)); +- +- printf("%d/%d sectors allocated at offset %s\n", +- sum_alloc, nb_sectors, s1); +- return 0; +-} +- +-static const cmdinfo_t alloc_cmd = { +- .name = "alloc", +- .altname = "a", +- .argmin = 1, +- .argmax = 2, +- .cfunc = alloc_f, +- .args = "off [sectors]", +- .oneline = "checks if a sector is present in the file", +-}; +- +-static int map_f(BlockDriverState *bs, int argc, char **argv) +-{ +- int64_t offset; +- int64_t nb_sectors; +- char s1[64]; +- int num, num_checked; +- int ret; +- const char *retstr; +- +- offset = 0; +- nb_sectors = bs->total_sectors; +- +- do { +- num_checked = MIN(nb_sectors, INT_MAX); +- ret = bdrv_is_allocated(bs, offset, num_checked, &num); +- retstr = ret ? " allocated" : "not allocated"; +- cvtstr(offset << 9ULL, s1, sizeof(s1)); +- printf("[% 24" PRId64 "] % 8d/% 8d sectors %s at offset %s (%d)\n", +- offset << 9ULL, num, num_checked, retstr, s1, ret); +- +- offset += num; +- nb_sectors -= num; +- } while (offset < bs->total_sectors); +- +- return 0; +-} +- +-static const cmdinfo_t map_cmd = { +- .name = "map", +- .argmin = 0, +- .argmax = 0, +- .cfunc = map_f, +- .args = "", +- .oneline = "prints the allocated areas of a file", +-}; +- +-static int break_f(BlockDriverState *bs, int argc, char **argv) +-{ +- int ret; +- +- ret = bdrv_debug_breakpoint(bs, argv[1], argv[2]); +- if (ret < 0) { +- printf("Could not set breakpoint: %s\n", strerror(-ret)); +- } +- +- return 0; +-} +- +-static const cmdinfo_t break_cmd = { +- .name = "break", +- .argmin = 2, +- .argmax = 2, +- .cfunc = break_f, +- .args = "event tag", +- .oneline = "sets a breakpoint on event and tags the stopped " +- "request as tag", +-}; +- +-static int resume_f(BlockDriverState *bs, int argc, char **argv) +-{ +- int ret; +- +- ret = bdrv_debug_resume(bs, argv[1]); +- if (ret < 0) { +- printf("Could not resume request: %s\n", strerror(-ret)); +- } +- +- return 0; +-} +- +-static const cmdinfo_t resume_cmd = { +- .name = "resume", +- .argmin = 1, +- .argmax = 1, +- .cfunc = resume_f, +- .args = "tag", +- .oneline = "resumes the request tagged as tag", +-}; +- +-static int wait_break_f(BlockDriverState *bs, int argc, char **argv) +-{ +- while (!bdrv_debug_is_suspended(bs, argv[1])) { +- qemu_aio_wait(); +- } +- +- return 0; +-} +- +-static const cmdinfo_t wait_break_cmd = { +- .name = "wait_break", +- .argmin = 1, +- .argmax = 1, +- .cfunc = wait_break_f, +- .args = "tag", +- .oneline = "waits for the suspension of a request", +-}; +- +-static int abort_f(BlockDriverState *bs, int argc, char **argv) +-{ +- abort(); +-} +- +-static const cmdinfo_t abort_cmd = { +- .name = "abort", +- .cfunc = abort_f, +- .flags = CMD_NOFILE_OK, +- .oneline = "simulate a program crash using abort(3)", +-}; ++extern int qemuio_misalign; + + static int close_f(BlockDriverState *bs, int argc, char **argv) + { +@@ -1801,45 +48,6 @@ static const cmdinfo_t close_cmd = { + .oneline = "close the current open file", + }; + +-static void sleep_cb(void *opaque) +-{ +- bool *expired = opaque; +- *expired = true; +-} +- +-static int sleep_f(BlockDriverState *bs, int argc, char **argv) +-{ +- char *endptr; +- long ms; +- struct QEMUTimer *timer; +- bool expired = false; +- +- ms = strtol(argv[1], &endptr, 0); +- if (ms < 0 || *endptr != '\0') { +- printf("%s is not a valid number\n", argv[1]); +- return 0; +- } +- +- timer = qemu_new_timer_ns(host_clock, sleep_cb, &expired); +- qemu_mod_timer(timer, qemu_get_clock_ns(host_clock) + SCALE_MS * ms); +- +- while (!expired) { +- main_loop_wait(false); +- } +- +- qemu_free_timer(timer); +- +- return 0; +-} +- +-static const cmdinfo_t sleep_cmd = { +- .name = "sleep", +- .argmin = 1, +- .argmax = 1, +- .cfunc = sleep_f, +- .flags = CMD_NOFILE_OK, +- .oneline = "waits for the given value in milliseconds", +-}; + + static int openfile(char *name, int flags, int growable, QDict *opts) + { +@@ -1962,18 +170,6 @@ static int open_f(BlockDriverState *bs, int argc, char **argv) + return openfile(argv[optind], flags, growable, opts); + } + +-static int init_check_command(BlockDriverState *bs, const cmdinfo_t *ct) +-{ +- if (ct->flags & CMD_FLAG_GLOBAL) { +- return 1; +- } +- if (!(ct->flags & CMD_NOFILE_OK) && !bs) { +- fprintf(stderr, "no file open, try 'help open'\n"); +- return 0; +- } +- return 1; +-} +- + static void usage(const char *name) + { + printf( +@@ -2049,7 +245,7 @@ int main(int argc, char **argv) + readonly = 1; + break; + case 'm': +- misalign = 1; ++ qemuio_misalign = 1; + break; + case 'g': + growable = 1; +@@ -2090,31 +286,8 @@ int main(int argc, char **argv) + + /* initialize commands */ + quit_init(); +- help_init(); + add_command(&open_cmd); + add_command(&close_cmd); +- add_command(&read_cmd); +- add_command(&readv_cmd); +- add_command(&write_cmd); +- add_command(&writev_cmd); +- add_command(&multiwrite_cmd); +- add_command(&aio_read_cmd); +- add_command(&aio_write_cmd); +- add_command(&aio_flush_cmd); +- add_command(&flush_cmd); +- add_command(&truncate_cmd); +- add_command(&length_cmd); +- add_command(&info_cmd); +- add_command(&discard_cmd); +- add_command(&alloc_cmd); +- add_command(&map_cmd); +- add_command(&break_cmd); +- add_command(&resume_cmd); +- add_command(&wait_break_cmd); +- add_command(&abort_cmd); +- add_command(&sleep_cmd); +- +- add_check_command(init_check_command); + + /* open the device */ + if (!readonly) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-Use-the-qemu-version-for-V.patch b/SOURCES/kvm-qemu-io-Use-the-qemu-version-for-V.patch new file mode 100644 index 0000000..a2622d6 --- /dev/null +++ b/SOURCES/kvm-qemu-io-Use-the-qemu-version-for-V.patch @@ -0,0 +1,54 @@ +From 883449501b5d87002bb01c2a060cf650acf45d9a Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:34 +0100 +Subject: [PATCH 15/27] qemu-io: Use the qemu version for -V + +RH-Author: John Snow +Message-id: <1448300320-7772-16-git-send-email-jsnow@redhat.com> +Patchwork-id: 68442 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 15/21] qemu-io: Use the qemu version for -V +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +From: Kevin Wolf + +Always printing 0.0.1 and never updating the version number wasn't very +useful. qemu-io is released with qemu, so using the same version number +makes most sense. + +Signed-off-by: Kevin Wolf +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 02da386a2d7a020e80b0aed64769efa9dd42072a) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina +--- + qemu-io.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/qemu-io.c b/qemu-io.c +index e685808..16b2d8a 100644 +--- a/qemu-io.c ++++ b/qemu-io.c +@@ -23,8 +23,6 @@ + #include "trace/control.h" + #include "qemu/timer.h" + +-#define VERSION "0.0.1" +- + #define CMD_NOFILE_OK 0x01 + + char *progname; +@@ -418,7 +416,7 @@ int main(int argc, char **argv) + } + break; + case 'V': +- printf("%s version %s\n", progname, VERSION); ++ printf("%s version %s\n", progname, QEMU_VERSION); + exit(0); + case 'h': + usage(progname); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qemu-io-fix-cvtnum-lval-types.patch b/SOURCES/kvm-qemu-io-fix-cvtnum-lval-types.patch new file mode 100644 index 0000000..9372946 --- /dev/null +++ b/SOURCES/kvm-qemu-io-fix-cvtnum-lval-types.patch @@ -0,0 +1,360 @@ +From a5226789eaaedf06f50f2faf14b506c17deb5435 Mon Sep 17 00:00:00 2001 +From: John Snow +Date: Mon, 23 Nov 2015 17:38:37 +0100 +Subject: [PATCH 18/27] qemu-io: fix cvtnum lval types + +RH-Author: John Snow +Message-id: <1448300320-7772-19-git-send-email-jsnow@redhat.com> +Patchwork-id: 68445 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 18/21] qemu-io: fix cvtnum lval types +Bugzilla: 1272523 +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Max Reitz + +cvtnum() returns int64_t: we should not be storing this +result inside of an int. + +In a few cases, we need an extra sprinkling of error handling +where we expect to pass this number on towards a function that +expects something smaller than int64_t. + +Reported-by: Max Reitz +Signed-off-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit 9b0beaf3de1396a23d5c287283e6f36c4b5d4385) +Signed-off-by: John Snow +Signed-off-by: Miroslav Rezanina + +Conflicts: + qemu-io-cmds.c: + - Upstream uses blk_xxx commands, while downstream uses bdrv_xxx + - Fixes to sigraise are not backported. + +Signed-off-by: John Snow +--- + qemu-io-cmds.c | 119 ++++++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 84 insertions(+), 35 deletions(-) + +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index 1f21ce9..95345fe 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -282,9 +282,10 @@ static void qemu_io_free(void *p) + qemu_vfree(p); + } + +-static void dump_buffer(const void *buffer, int64_t offset, int len) ++static void dump_buffer(const void *buffer, int64_t offset, int64_t len) + { +- int i, j; ++ uint64_t i; ++ int j; + const uint8_t *p; + + for (i = 0, p = buffer; i < len; i += 16) { +@@ -307,7 +308,7 @@ static void dump_buffer(const void *buffer, int64_t offset, int len) + } + + static void print_report(const char *op, struct timeval *t, int64_t offset, +- int count, int total, int cnt, int Cflag) ++ int64_t count, int64_t total, int cnt, int Cflag) + { + char s1[64], s2[64], ts[64]; + +@@ -315,12 +316,12 @@ static void print_report(const char *op, struct timeval *t, int64_t offset, + if (!Cflag) { + cvtstr((double)total, s1, sizeof(s1)); + cvtstr(tdiv((double)total, *t), s2, sizeof(s2)); +- printf("%s %d/%d bytes at offset %" PRId64 "\n", ++ printf("%s %"PRId64"/%"PRId64" bytes at offset %" PRId64 "\n", + op, total, count, offset); + printf("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n", + s1, cnt, ts, s2, tdiv((double)cnt, *t)); + } else {/* bytes,ops,time,bytes/sec,ops/sec */ +- printf("%d,%d,%s,%.3f,%.3f\n", ++ printf("%"PRId64",%d,%s,%.3f,%.3f\n", + total, cnt, ts, + tdiv((double)total, *t), + tdiv((double)cnt, *t)); +@@ -381,11 +382,15 @@ fail: + return buf; + } + +-static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count, +- int *total) ++static int do_read(BlockDriverState *bs, char *buf, int64_t offset, ++ int64_t count, int64_t *total) + { + int ret; + ++ if (count >> 9 > INT_MAX) { ++ return -ERANGE; ++ } ++ + ret = bdrv_read(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (ret < 0) { + return ret; +@@ -394,11 +399,15 @@ static int do_read(BlockDriverState *bs, char *buf, int64_t offset, int count, + return 1; + } + +-static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count, +- int *total) ++static int do_write(BlockDriverState *bs, char *buf, int64_t offset, ++ int64_t count, int64_t *total) + { + int ret; + ++ if (count >> 9 > INT_MAX) { ++ return -ERANGE; ++ } ++ + ret = bdrv_write(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (ret < 0) { + return ret; +@@ -407,9 +416,13 @@ static int do_write(BlockDriverState *bs, char *buf, int64_t offset, int count, + return 1; + } + +-static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count, +- int *total) ++static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, ++ int64_t count, int64_t *total) + { ++ if (count > INT_MAX) { ++ return -ERANGE; ++ } ++ + *total = bdrv_pread(bs, offset, (uint8_t *)buf, count); + if (*total < 0) { + return *total; +@@ -417,9 +430,13 @@ static int do_pread(BlockDriverState *bs, char *buf, int64_t offset, int count, + return 1; + } + +-static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count, +- int *total) ++static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, ++ int64_t count, int64_t *total) + { ++ if (count > INT_MAX) { ++ return -ERANGE; ++ } ++ + *total = bdrv_pwrite(bs, offset, (uint8_t *)buf, count); + if (*total < 0) { + return *total; +@@ -430,8 +447,8 @@ static int do_pwrite(BlockDriverState *bs, char *buf, int64_t offset, int count, + typedef struct { + BlockDriverState *bs; + int64_t offset; +- int count; +- int *total; ++ int64_t count; ++ int64_t *total; + int ret; + bool done; + } CoWriteZeroes; +@@ -451,8 +468,8 @@ static void coroutine_fn co_write_zeroes_entry(void *opaque) + *data->total = data->count; + } + +-static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, +- int *total) ++static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, ++ int64_t count, int64_t *total) + { + Coroutine *co; + CoWriteZeroes data = { +@@ -463,6 +480,10 @@ static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, + .done = false, + }; + ++ if (count >> BDRV_SECTOR_BITS > INT_MAX) { ++ return -ERANGE; ++ } ++ + co = qemu_coroutine_create(co_write_zeroes_entry); + qemu_coroutine_enter(co, &data); + while (!data.done) { +@@ -476,10 +497,14 @@ static int do_co_write_zeroes(BlockDriverState *bs, int64_t offset, int count, + } + + static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset, +- int count, int *total) ++ int64_t count, int64_t *total) + { + int ret; + ++ if (count >> 9 > INT_MAX) { ++ return -ERANGE; ++ } ++ + ret = bdrv_write_compressed(bs, offset >> 9, (uint8_t *)buf, count >> 9); + if (ret < 0) { + return ret; +@@ -489,8 +514,12 @@ static int do_write_compressed(BlockDriverState *bs, char *buf, int64_t offset, + } + + static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset, +- int count, int *total) ++ int64_t count, int64_t *total) + { ++ if (count > INT_MAX) { ++ return -ERANGE; ++ } ++ + *total = bdrv_load_vmstate(bs, (uint8_t *)buf, offset, count); + if (*total < 0) { + return *total; +@@ -499,8 +528,12 @@ static int do_load_vmstate(BlockDriverState *bs, char *buf, int64_t offset, + } + + static int do_save_vmstate(BlockDriverState *bs, char *buf, int64_t offset, +- int count, int *total) ++ int64_t count, int64_t *total) + { ++ if (count > INT_MAX) { ++ return -ERANGE; ++ } ++ + *total = bdrv_save_vmstate(bs, (uint8_t *)buf, offset, count); + if (*total < 0) { + return *total; +@@ -630,10 +663,11 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) + int c, cnt; + char *buf; + int64_t offset; +- int count; ++ int64_t count; + /* Some compilers get confused and warn if this is not initialized. */ +- int total = 0; +- int pattern = 0, pattern_offset = 0, pattern_count = 0; ++ int64_t total = 0; ++ int pattern = 0; ++ int64_t pattern_offset = 0, pattern_count = 0; + + while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != EOF) { + switch (c) { +@@ -700,6 +734,10 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) + if (count < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; ++ } else if (count > SIZE_MAX) { ++ printf("length cannot exceed %" PRIu64 ", given %s\n", ++ (uint64_t) SIZE_MAX, argv[optind]); ++ return 0; + } + + if (!Pflag && (lflag || sflag)) { +@@ -722,7 +760,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) + return 0; + } + if (count & 0x1ff) { +- printf("count %d is not sector aligned\n", ++ printf("count %"PRId64" is not sector aligned\n", + count); + return 0; + } +@@ -750,7 +788,7 @@ static int read_f(BlockDriverState *bs, int argc, char **argv) + memset(cmp_buf, pattern, pattern_count); + if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) { + printf("Pattern verification failed at offset %" +- PRId64 ", %d bytes\n", ++ PRId64 ", %"PRId64" bytes\n", + offset + pattern_offset, pattern_count); + } + g_free(cmp_buf); +@@ -945,9 +983,9 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) + int c, cnt; + char *buf = NULL; + int64_t offset; +- int count; ++ int64_t count; + /* Some compilers get confused and warn if this is not initialized. */ +- int total = 0; ++ int64_t total = 0; + int pattern = 0xcd; + + while ((c = getopt(argc, argv, "bcCpP:qz")) != EOF) { +@@ -1007,6 +1045,10 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) + if (count < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; ++ } else if (count > SIZE_MAX) { ++ printf("length cannot exceed %" PRIu64 ", given %s\n", ++ (uint64_t) SIZE_MAX, argv[optind]); ++ return 0; + } + + if (!pflag) { +@@ -1017,7 +1059,7 @@ static int write_f(BlockDriverState *bs, int argc, char **argv) + } + + if (count & 0x1ff) { +- printf("count %d is not sector aligned\n", ++ printf("count %"PRId64" is not sector aligned\n", + count); + return 0; + } +@@ -1752,8 +1794,7 @@ static int discard_f(BlockDriverState *bs, int argc, char **argv) + struct timeval t1, t2; + int Cflag = 0, qflag = 0; + int c, ret; +- int64_t offset; +- int count; ++ int64_t offset, count; + + while ((c = getopt(argc, argv, "Cq")) != EOF) { + switch (c) { +@@ -1783,6 +1824,11 @@ static int discard_f(BlockDriverState *bs, int argc, char **argv) + if (count < 0) { + printf("non-numeric length argument -- %s\n", argv[optind]); + return 0; ++ } else if (count >> BDRV_SECTOR_BITS > INT_MAX) { ++ printf("length cannot exceed %"PRIu64", given %s\n", ++ (uint64_t)INT_MAX << BDRV_SECTOR_BITS, ++ argv[optind]); ++ return 0; + } + + gettimeofday(&t1, NULL); +@@ -1807,11 +1853,10 @@ out: + + static int alloc_f(BlockDriverState *bs, int argc, char **argv) + { +- int64_t offset, sector_num; +- int nb_sectors, remaining; ++ int64_t offset, sector_num, nb_sectors, remaining; + char s1[64]; +- int num, sum_alloc; +- int ret; ++ int num, ret; ++ int64_t sum_alloc; + + offset = cvtnum(argv[1]); + if (offset < 0) { +@@ -1828,6 +1873,10 @@ static int alloc_f(BlockDriverState *bs, int argc, char **argv) + if (nb_sectors < 0) { + printf("non-numeric length argument -- %s\n", argv[2]); + return 0; ++ } else if (nb_sectors > INT_MAX) { ++ printf("length argument cannot exceed %d, given %s\n", ++ INT_MAX, argv[2]); ++ return 0; + } + } else { + nb_sectors = 1; +@@ -1855,7 +1904,7 @@ static int alloc_f(BlockDriverState *bs, int argc, char **argv) + + cvtstr(offset, s1, sizeof(s1)); + +- printf("%d/%d sectors allocated at offset %s\n", ++ printf("%"PRId64"/%"PRId64" sectors allocated at offset %s\n", + sum_alloc, nb_sectors, s1); + return 0; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-Apply-nesting-limit-more-sanely.patch b/SOURCES/kvm-qjson-Apply-nesting-limit-more-sanely.patch new file mode 100644 index 0000000..061218c --- /dev/null +++ b/SOURCES/kvm-qjson-Apply-nesting-limit-more-sanely.patch @@ -0,0 +1,46 @@ +From 1f08301adf98c235ccc4e978f809c3f60833452c Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:00 +0200 +Subject: [PATCH 02/16] qjson: Apply nesting limit more sanely + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-4-git-send-email-armbru@redhat.com> +Patchwork-id: 71468 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 02/15] qjson: Apply nesting limit more sanely +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +The nesting limit from commit 29c75dd "json-streamer: limit the +maximum recursion depth and maximum token count" applies separately to +braces and brackets. This makes no sense. Apply it to their sum, +because that's actually a measure of recursion depth. + +Signed-off-by: Markus Armbruster +Reviewed-by: Eric Blake +Message-Id: <1448486613-17634-2-git-send-email-armbru@redhat.com> +(cherry picked from commit 4f2d31fbc0bfdf41feea7d1be49f4f7ffa005534) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + qobject/json-streamer.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c +index 1b2f9b1..dced2c7 100644 +--- a/qobject/json-streamer.c ++++ b/qobject/json-streamer.c +@@ -64,8 +64,7 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok + parser->bracket_count == 0)) { + goto out_emit; + } else if (parser->token_size > MAX_TOKEN_SIZE || +- parser->bracket_count > MAX_NESTING || +- parser->brace_count > MAX_NESTING) { ++ parser->bracket_count + parser->brace_count > MAX_NESTING) { + /* Security consideration, we limit total memory allocated per object + * and the maximum recursion depth that a message can force. + */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-Convert-to-parser-to-recursive-descent.patch b/SOURCES/kvm-qjson-Convert-to-parser-to-recursive-descent.patch new file mode 100644 index 0000000..2da74a2 --- /dev/null +++ b/SOURCES/kvm-qjson-Convert-to-parser-to-recursive-descent.patch @@ -0,0 +1,328 @@ +From 2975abb487a54b49246646db9aa40ee6d1beaa97 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:08 +0200 +Subject: [PATCH 10/16] qjson: Convert to parser to recursive descent + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-12-git-send-email-armbru@redhat.com> +Patchwork-id: 71474 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 10/15] qjson: Convert to parser to recursive descent +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +We backtrack in parse_value(), even though JSON is LL(1) and thus can +be parsed by straightforward recursive descent. Do exactly that. + +Based on an almost-correct patch from Paolo Bonzini. + +Signed-off-by: Paolo Bonzini +Signed-off-by: Markus Armbruster +Message-Id: <1448486613-17634-10-git-send-email-armbru@redhat.com> +Reviewed-by: Eric Blake +(cherry picked from commit d538b25543f4db026bb435066e2403a542522c40) +Signed-off-by: Miroslav Rezanina + +Conflicts: + qobject/json-parser.c + +Straighforward conflicts because lacking commit fc48ffc "qobject: Use +'bool' for qbool", we still use qbool_from_int(), and we lack commit +e549e71 "json-parser: Accept 'null' in QMP". + +Signed-off-by: Markus Armbruster +--- + qobject/json-parser.c | 163 ++++++++++++++------------------------------------ + 1 file changed, 46 insertions(+), 117 deletions(-) + +diff --git a/qobject/json-parser.c b/qobject/json-parser.c +index 79f4173..b242fba 100644 +--- a/qobject/json-parser.c ++++ b/qobject/json-parser.c +@@ -266,23 +266,6 @@ static QObject *parser_context_peek_token(JSONParserContext *ctxt) + return token; + } + +-static JSONParserContext parser_context_save(JSONParserContext *ctxt) +-{ +- JSONParserContext saved_ctxt = {0}; +- saved_ctxt.tokens.pos = ctxt->tokens.pos; +- saved_ctxt.tokens.count = ctxt->tokens.count; +- saved_ctxt.tokens.buf = ctxt->tokens.buf; +- return saved_ctxt; +-} +- +-static void parser_context_restore(JSONParserContext *ctxt, +- JSONParserContext saved_ctxt) +-{ +- ctxt->tokens.pos = saved_ctxt.tokens.pos; +- ctxt->tokens.count = saved_ctxt.tokens.count; +- ctxt->tokens.buf = saved_ctxt.tokens.buf; +-} +- + static void tokens_append_from_iter(QObject *obj, void *opaque) + { + JSONParserContext *ctxt = opaque; +@@ -334,7 +317,6 @@ static void parser_context_free(JSONParserContext *ctxt) + static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap) + { + QObject *key = NULL, *token = NULL, *value, *peek; +- JSONParserContext saved_ctxt = parser_context_save(ctxt); + + peek = parser_context_peek_token(ctxt); + if (peek == NULL) { +@@ -372,7 +354,6 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap) + return 0; + + out: +- parser_context_restore(ctxt, saved_ctxt); + qobject_decref(key); + + return -1; +@@ -382,16 +363,9 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + { + QDict *dict = NULL; + QObject *token, *peek; +- JSONParserContext saved_ctxt = parser_context_save(ctxt); + + token = parser_context_pop_token(ctxt); +- if (token == NULL) { +- goto out; +- } +- +- if (token_get_type(token) != JSON_LCURLY) { +- goto out; +- } ++ assert(token && token_get_type(token) == JSON_LCURLY); + + dict = qdict_new(); + +@@ -435,7 +409,6 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + return QOBJECT(dict); + + out: +- parser_context_restore(ctxt, saved_ctxt); + QDECREF(dict); + return NULL; + } +@@ -444,16 +417,9 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + { + QList *list = NULL; + QObject *token, *peek; +- JSONParserContext saved_ctxt = parser_context_save(ctxt); + + token = parser_context_pop_token(ctxt); +- if (token == NULL) { +- goto out; +- } +- +- if (token_get_type(token) != JSON_LSQUARE) { +- goto out; +- } ++ assert(token && token_get_type(token) == JSON_LSQUARE); + + list = qlist_new(); + +@@ -507,107 +473,70 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + return QOBJECT(list); + + out: +- parser_context_restore(ctxt, saved_ctxt); + QDECREF(list); + return NULL; + } + + static QObject *parse_keyword(JSONParserContext *ctxt) + { +- QObject *token, *ret; +- JSONParserContext saved_ctxt = parser_context_save(ctxt); ++ QObject *token; + const char *val; + + token = parser_context_pop_token(ctxt); +- if (token == NULL) { +- goto out; +- } +- +- if (token_get_type(token) != JSON_KEYWORD) { +- goto out; +- } +- ++ assert(token && token_get_type(token) == JSON_KEYWORD); + val = token_get_value(token); + + if (!strcmp(val, "true")) { +- ret = QOBJECT(qbool_from_int(true)); ++ return QOBJECT(qbool_from_int(true)); + } else if (!strcmp(val, "false")) { +- ret = QOBJECT(qbool_from_int(false)); +- } else { +- parse_error(ctxt, token, "invalid keyword '%s'", val); +- goto out; ++ return QOBJECT(qbool_from_int(false)); + } +- +- return ret; +- +-out: +- parser_context_restore(ctxt, saved_ctxt); +- ++ parse_error(ctxt, token, "invalid keyword '%s'", val); + return NULL; + } + + static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap) + { +- QObject *token = NULL, *obj; +- JSONParserContext saved_ctxt = parser_context_save(ctxt); ++ QObject *token; + const char *val; + + if (ap == NULL) { +- goto out; ++ return NULL; + } + + token = parser_context_pop_token(ctxt); +- if (token == NULL) { +- goto out; +- } +- +- if (token_get_type(token) != JSON_ESCAPE) { +- goto out; +- } +- ++ assert(token && token_get_type(token) == JSON_ESCAPE); + val = token_get_value(token); + + if (!strcmp(val, "%p")) { +- obj = va_arg(*ap, QObject *); ++ return va_arg(*ap, QObject *); + } else if (!strcmp(val, "%i")) { +- obj = QOBJECT(qbool_from_int(va_arg(*ap, int))); ++ return QOBJECT(qbool_from_int(va_arg(*ap, int))); + } else if (!strcmp(val, "%d")) { +- obj = QOBJECT(qint_from_int(va_arg(*ap, int))); ++ return QOBJECT(qint_from_int(va_arg(*ap, int))); + } else if (!strcmp(val, "%ld")) { +- obj = QOBJECT(qint_from_int(va_arg(*ap, long))); ++ return QOBJECT(qint_from_int(va_arg(*ap, long))); + } else if (!strcmp(val, "%lld") || + !strcmp(val, "%I64d")) { +- obj = QOBJECT(qint_from_int(va_arg(*ap, long long))); ++ return QOBJECT(qint_from_int(va_arg(*ap, long long))); + } else if (!strcmp(val, "%s")) { +- obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *))); ++ return QOBJECT(qstring_from_str(va_arg(*ap, const char *))); + } else if (!strcmp(val, "%f")) { +- obj = QOBJECT(qfloat_from_double(va_arg(*ap, double))); +- } else { +- goto out; ++ return QOBJECT(qfloat_from_double(va_arg(*ap, double))); + } +- +- return obj; +- +-out: +- parser_context_restore(ctxt, saved_ctxt); +- + return NULL; + } + + static QObject *parse_literal(JSONParserContext *ctxt) + { +- QObject *token, *obj; +- JSONParserContext saved_ctxt = parser_context_save(ctxt); ++ QObject *token; + + token = parser_context_pop_token(ctxt); +- if (token == NULL) { +- goto out; +- } ++ assert(token); + + switch (token_get_type(token)) { + case JSON_STRING: +- obj = QOBJECT(qstring_from_escaped_str(ctxt, token)); +- break; ++ return QOBJECT(qstring_from_escaped_str(ctxt, token)); + case JSON_INTEGER: { + /* A possibility exists that this is a whole-valued float where the + * fractional part was left out due to being 0 (.0). It's not a big +@@ -626,46 +555,46 @@ static QObject *parse_literal(JSONParserContext *ctxt) + errno = 0; /* strtoll doesn't set errno on success */ + value = strtoll(token_get_value(token), NULL, 10); + if (errno != ERANGE) { +- obj = QOBJECT(qint_from_int(value)); +- break; ++ return QOBJECT(qint_from_int(value)); + } + /* fall through to JSON_FLOAT */ + } + case JSON_FLOAT: + /* FIXME dependent on locale */ +- obj = QOBJECT(qfloat_from_double(strtod(token_get_value(token), NULL))); +- break; ++ return QOBJECT(qfloat_from_double(strtod(token_get_value(token), ++ NULL))); + default: +- goto out; ++ abort(); + } +- +- return obj; +- +-out: +- parser_context_restore(ctxt, saved_ctxt); +- +- return NULL; + } + + static QObject *parse_value(JSONParserContext *ctxt, va_list *ap) + { +- QObject *obj; ++ QObject *token; + +- obj = parse_object(ctxt, ap); +- if (obj == NULL) { +- obj = parse_array(ctxt, ap); +- } +- if (obj == NULL) { +- obj = parse_escape(ctxt, ap); +- } +- if (obj == NULL) { +- obj = parse_keyword(ctxt); +- } +- if (obj == NULL) { +- obj = parse_literal(ctxt); ++ token = parser_context_peek_token(ctxt); ++ if (token == NULL) { ++ parse_error(ctxt, NULL, "premature EOI"); ++ return NULL; + } + +- return obj; ++ switch (token_get_type(token)) { ++ case JSON_LCURLY: ++ return parse_object(ctxt, ap); ++ case JSON_LSQUARE: ++ return parse_array(ctxt, ap); ++ case JSON_ESCAPE: ++ return parse_escape(ctxt, ap); ++ case JSON_INTEGER: ++ case JSON_FLOAT: ++ case JSON_STRING: ++ return parse_literal(ctxt); ++ case JSON_KEYWORD: ++ return parse_keyword(ctxt); ++ default: ++ parse_error(ctxt, token, "expecting value"); ++ return NULL; ++ } + } + + QObject *json_parser_parse(QList *tokens, va_list *ap) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-Don-t-crash-when-input-exceeds-nesting-limit.patch b/SOURCES/kvm-qjson-Don-t-crash-when-input-exceeds-nesting-limit.patch new file mode 100644 index 0000000..e8ac2fa --- /dev/null +++ b/SOURCES/kvm-qjson-Don-t-crash-when-input-exceeds-nesting-limit.patch @@ -0,0 +1,62 @@ +From ba9229d280e035872ac2258873c1b9f34cc8c4a9 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:01 +0200 +Subject: [PATCH 03/16] qjson: Don't crash when input exceeds nesting limit + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-5-git-send-email-armbru@redhat.com> +Patchwork-id: 71472 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 03/15] qjson: Don't crash when input exceeds nesting limit +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +We limit nesting depth and input size to defend against input +triggering excessive heap or stack memory use (commit 29c75dd +json-streamer: limit the maximum recursion depth and maximum token +count). However, when the nesting limit is exceeded, +parser_context_peek_token()'s assertion fails. + +Broken in commit 65c0f1e "json-parser: don't replicate tokens at each +level of recursion". + +To reproduce stuff 1025 open braces or brackets into QMP. + +Fix by taking the error exit instead of the normal one. + +Reported-by: Eric Blake +Signed-off-by: Markus Armbruster +Reviewed-by: Eric Blake +Message-Id: <1448486613-17634-3-git-send-email-armbru@redhat.com> +(cherry picked from commit 0753113a26bb8c77f951b1ea91fd4f36d099c37a) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + qobject/json-streamer.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c +index dced2c7..2bd22a7 100644 +--- a/qobject/json-streamer.c ++++ b/qobject/json-streamer.c +@@ -68,13 +68,14 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok + /* Security consideration, we limit total memory allocated per object + * and the maximum recursion depth that a message can force. + */ +- goto out_emit; ++ goto out_emit_bad; + } + + return; + + out_emit_bad: +- /* clear out token list and tell the parser to emit and error ++ /* ++ * Clear out token list and tell the parser to emit an error + * indication by passing it a NULL list + */ + QDECREF(parser->tokens); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-Give-each-of-the-six-structural-chars-its-own-.patch b/SOURCES/kvm-qjson-Give-each-of-the-six-structural-chars-its-own-.patch new file mode 100644 index 0000000..a007310 --- /dev/null +++ b/SOURCES/kvm-qjson-Give-each-of-the-six-structural-chars-its-own-.patch @@ -0,0 +1,222 @@ +From 95aeff93da762bf7f69317eb674d3eccce672038 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:04 +0200 +Subject: [PATCH 06/16] qjson: Give each of the six structural chars its own + token type + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-8-git-send-email-armbru@redhat.com> +Patchwork-id: 71482 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 06/15] qjson: Give each of the six structural chars its own token type +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +Simplifies things, because we always check for a specific one. + +Signed-off-by: Markus Armbruster +Message-Id: <1448486613-17634-6-git-send-email-armbru@redhat.com> +Reviewed-by: Eric Blake +(cherry picked from commit c54616608af442edf4cfb7397a1909c2653efba0) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + include/qapi/qmp/json-lexer.h | 7 ++++++- + qobject/json-lexer.c | 19 ++++++++++++------- + qobject/json-parser.c | 31 +++++++++---------------------- + qobject/json-streamer.c | 32 +++++++++++++++----------------- + 4 files changed, 42 insertions(+), 47 deletions(-) + +diff --git a/include/qapi/qmp/json-lexer.h b/include/qapi/qmp/json-lexer.h +index 61a143f..f3e8dc7 100644 +--- a/include/qapi/qmp/json-lexer.h ++++ b/include/qapi/qmp/json-lexer.h +@@ -19,7 +19,12 @@ + + typedef enum json_token_type { + JSON_MIN = 100, +- JSON_OPERATOR = JSON_MIN, ++ JSON_LCURLY = JSON_MIN, ++ JSON_RCURLY, ++ JSON_LSQUARE, ++ JSON_RSQUARE, ++ JSON_COLON, ++ JSON_COMMA, + JSON_INTEGER, + JSON_FLOAT, + JSON_KEYWORD, +diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c +index f106ffb..1bfff02 100644 +--- a/qobject/json-lexer.c ++++ b/qobject/json-lexer.c +@@ -257,12 +257,12 @@ static const uint8_t json_lexer[][256] = { + ['0'] = IN_ZERO, + ['1' ... '9'] = IN_NONZERO_NUMBER, + ['-'] = IN_NEG_NONZERO_NUMBER, +- ['{'] = JSON_OPERATOR, +- ['}'] = JSON_OPERATOR, +- ['['] = JSON_OPERATOR, +- [']'] = JSON_OPERATOR, +- [','] = JSON_OPERATOR, +- [':'] = JSON_OPERATOR, ++ ['{'] = JSON_LCURLY, ++ ['}'] = JSON_RCURLY, ++ ['['] = JSON_LSQUARE, ++ [']'] = JSON_RSQUARE, ++ [','] = JSON_COMMA, ++ [':'] = JSON_COLON, + ['a' ... 'z'] = IN_KEYWORD, + ['%'] = IN_ESCAPE, + [' '] = IN_WHITESPACE, +@@ -299,7 +299,12 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush) + } + + switch (new_state) { +- case JSON_OPERATOR: ++ case JSON_LCURLY: ++ case JSON_RCURLY: ++ case JSON_LSQUARE: ++ case JSON_RSQUARE: ++ case JSON_COLON: ++ case JSON_COMMA: + case JSON_ESCAPE: + case JSON_INTEGER: + case JSON_FLOAT: +diff --git a/qobject/json-parser.c b/qobject/json-parser.c +index fa09769..50bf30c 100644 +--- a/qobject/json-parser.c ++++ b/qobject/json-parser.c +@@ -64,19 +64,6 @@ static JSONTokenType token_get_type(QObject *obj) + return qdict_get_int(qobject_to_qdict(obj), "type"); + } + +-static int token_is_operator(QObject *obj, char op) +-{ +- const char *val; +- +- if (token_get_type(obj) != JSON_OPERATOR) { +- return 0; +- } +- +- val = token_get_value(obj); +- +- return (val[0] == op) && (val[1] == 0); +-} +- + static int token_is_keyword(QObject *obj, const char *value) + { + if (token_get_type(obj) != JSON_KEYWORD) { +@@ -385,7 +372,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap) + goto out; + } + +- if (!token_is_operator(token, ':')) { ++ if (token_get_type(token) != JSON_COLON) { + parse_error(ctxt, token, "missing : in object pair"); + goto out; + } +@@ -420,7 +407,7 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- if (!token_is_operator(token, '{')) { ++ if (token_get_type(token) != JSON_LCURLY) { + goto out; + } + +@@ -432,7 +419,7 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- if (!token_is_operator(peek, '}')) { ++ if (token_get_type(peek) != JSON_RCURLY) { + if (parse_pair(ctxt, dict, ap) == -1) { + goto out; + } +@@ -443,8 +430,8 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- while (!token_is_operator(token, '}')) { +- if (!token_is_operator(token, ',')) { ++ while (token_get_type(token) != JSON_RCURLY) { ++ if (token_get_type(token) != JSON_COMMA) { + parse_error(ctxt, token, "expected separator in dict"); + goto out; + } +@@ -482,7 +469,7 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- if (!token_is_operator(token, '[')) { ++ if (token_get_type(token) != JSON_LSQUARE) { + goto out; + } + +@@ -494,7 +481,7 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- if (!token_is_operator(peek, ']')) { ++ if (token_get_type(peek) != JSON_RSQUARE) { + QObject *obj; + + obj = parse_value(ctxt, ap); +@@ -511,8 +498,8 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- while (!token_is_operator(token, ']')) { +- if (!token_is_operator(token, ',')) { ++ while (token_get_type(token) != JSON_RSQUARE) { ++ if (token_get_type(token) != JSON_COMMA) { + parse_error(ctxt, token, "expected separator in list"); + goto out; + } +diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c +index 2bd22a7..4a161a1 100644 +--- a/qobject/json-streamer.c ++++ b/qobject/json-streamer.c +@@ -26,23 +26,21 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok + JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer); + QDict *dict; + +- if (type == JSON_OPERATOR) { +- switch (qstring_get_str(token)[0]) { +- case '{': +- parser->brace_count++; +- break; +- case '}': +- parser->brace_count--; +- break; +- case '[': +- parser->bracket_count++; +- break; +- case ']': +- parser->bracket_count--; +- break; +- default: +- break; +- } ++ switch (type) { ++ case JSON_LCURLY: ++ parser->brace_count++; ++ break; ++ case JSON_RCURLY: ++ parser->brace_count--; ++ break; ++ case JSON_LSQUARE: ++ parser->bracket_count++; ++ break; ++ case JSON_RSQUARE: ++ parser->bracket_count--; ++ break; ++ default: ++ break; + } + + dict = qdict_new(); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-Inline-token_is_escape-and-simplify.patch b/SOURCES/kvm-qjson-Inline-token_is_escape-and-simplify.patch new file mode 100644 index 0000000..8ed2c95 --- /dev/null +++ b/SOURCES/kvm-qjson-Inline-token_is_escape-and-simplify.patch @@ -0,0 +1,97 @@ +From 225cb3d48dd4dcbc7bf845c0b4b06a90030874f3 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:06 +0200 +Subject: [PATCH 08/16] qjson: Inline token_is_escape() and simplify + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-10-git-send-email-armbru@redhat.com> +Patchwork-id: 71479 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 08/15] qjson: Inline token_is_escape() and simplify +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +Signed-off-by: Markus Armbruster +Message-Id: <1448486613-17634-8-git-send-email-armbru@redhat.com> +Reviewed-by: Eric Blake +(cherry picked from commit 6b9606f68ec589def27bd2a9cea97ec63cffd581) +Signed-off-by: Miroslav Rezanina + +Conflicts: + qobject/json-parser.c + +Straighforward conflict because lacking commit fc48ffc "qobject: Use +'bool' for qbool", we still use qbool_from_int(). + +Signed-off-by: Markus Armbruster +--- + qobject/json-parser.c | 32 +++++++++++++++----------------- + 1 file changed, 15 insertions(+), 17 deletions(-) + +diff --git a/qobject/json-parser.c b/qobject/json-parser.c +index e3690de..79f4173 100644 +--- a/qobject/json-parser.c ++++ b/qobject/json-parser.c +@@ -64,15 +64,6 @@ static JSONTokenType token_get_type(QObject *obj) + return qdict_get_int(qobject_to_qdict(obj), "type"); + } + +-static int token_is_escape(QObject *obj, const char *value) +-{ +- if (token_get_type(obj) != JSON_ESCAPE) { +- return 0; +- } +- +- return (strcmp(token_get_value(obj), value) == 0); +-} +- + /** + * Error handler + */ +@@ -559,6 +550,7 @@ static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap) + { + QObject *token = NULL, *obj; + JSONParserContext saved_ctxt = parser_context_save(ctxt); ++ const char *val; + + if (ap == NULL) { + goto out; +@@ -569,20 +561,26 @@ static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- if (token_is_escape(token, "%p")) { ++ if (token_get_type(token) != JSON_ESCAPE) { ++ goto out; ++ } ++ ++ val = token_get_value(token); ++ ++ if (!strcmp(val, "%p")) { + obj = va_arg(*ap, QObject *); +- } else if (token_is_escape(token, "%i")) { ++ } else if (!strcmp(val, "%i")) { + obj = QOBJECT(qbool_from_int(va_arg(*ap, int))); +- } else if (token_is_escape(token, "%d")) { ++ } else if (!strcmp(val, "%d")) { + obj = QOBJECT(qint_from_int(va_arg(*ap, int))); +- } else if (token_is_escape(token, "%ld")) { ++ } else if (!strcmp(val, "%ld")) { + obj = QOBJECT(qint_from_int(va_arg(*ap, long))); +- } else if (token_is_escape(token, "%lld") || +- token_is_escape(token, "%I64d")) { ++ } else if (!strcmp(val, "%lld") || ++ !strcmp(val, "%I64d")) { + obj = QOBJECT(qint_from_int(va_arg(*ap, long long))); +- } else if (token_is_escape(token, "%s")) { ++ } else if (!strcmp(val, "%s")) { + obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *))); +- } else if (token_is_escape(token, "%f")) { ++ } else if (!strcmp(val, "%f")) { + obj = QOBJECT(qfloat_from_double(va_arg(*ap, double))); + } else { + goto out; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-Inline-token_is_keyword-and-simplify.patch b/SOURCES/kvm-qjson-Inline-token_is_keyword-and-simplify.patch new file mode 100644 index 0000000..f885b32 --- /dev/null +++ b/SOURCES/kvm-qjson-Inline-token_is_keyword-and-simplify.patch @@ -0,0 +1,81 @@ +From 3cf8ec8ff0ad3920ce23166b2576655bcd886c5a Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:05 +0200 +Subject: [PATCH 07/16] qjson: Inline token_is_keyword() and simplify + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-9-git-send-email-armbru@redhat.com> +Patchwork-id: 71483 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 07/15] qjson: Inline token_is_keyword() and simplify +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +Signed-off-by: Markus Armbruster +Message-Id: <1448486613-17634-7-git-send-email-armbru@redhat.com> +Reviewed-by: Eric Blake +(cherry picked from commit 50e2a467f5315fa36c547fb6330659ba45f6bb83) +Signed-off-by: Miroslav Rezanina + +Conflicts: + qobject/json-parser.c + +Straighforward conflict because lacking commit fc48ffc "qobject: Use +'bool' for qbool", we still use qbool_from_int(), and we lack commit +e549e71 "json-parser: Accept 'null' in QMP". + +Signed-off-by: Markus Armbruster +--- + qobject/json-parser.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +diff --git a/qobject/json-parser.c b/qobject/json-parser.c +index 50bf30c..e3690de 100644 +--- a/qobject/json-parser.c ++++ b/qobject/json-parser.c +@@ -64,15 +64,6 @@ static JSONTokenType token_get_type(QObject *obj) + return qdict_get_int(qobject_to_qdict(obj), "type"); + } + +-static int token_is_keyword(QObject *obj, const char *value) +-{ +- if (token_get_type(obj) != JSON_KEYWORD) { +- return 0; +- } +- +- return strcmp(token_get_value(obj), value) == 0; +-} +- + static int token_is_escape(QObject *obj, const char *value) + { + if (token_get_type(obj) != JSON_ESCAPE) { +@@ -534,6 +525,7 @@ static QObject *parse_keyword(JSONParserContext *ctxt) + { + QObject *token, *ret; + JSONParserContext saved_ctxt = parser_context_save(ctxt); ++ const char *val; + + token = parser_context_pop_token(ctxt); + if (token == NULL) { +@@ -544,12 +536,14 @@ static QObject *parse_keyword(JSONParserContext *ctxt) + goto out; + } + +- if (token_is_keyword(token, "true")) { ++ val = token_get_value(token); ++ ++ if (!strcmp(val, "true")) { + ret = QOBJECT(qbool_from_int(true)); +- } else if (token_is_keyword(token, "false")) { ++ } else if (!strcmp(val, "false")) { + ret = QOBJECT(qbool_from_int(false)); + } else { +- parse_error(ctxt, token, "invalid keyword `%s'", token_get_value(token)); ++ parse_error(ctxt, token, "invalid keyword '%s'", val); + goto out; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-Limit-number-of-tokens-in-addition-to-total-si.patch b/SOURCES/kvm-qjson-Limit-number-of-tokens-in-addition-to-total-si.patch new file mode 100644 index 0000000..94ec4c4 --- /dev/null +++ b/SOURCES/kvm-qjson-Limit-number-of-tokens-in-addition-to-total-si.patch @@ -0,0 +1,59 @@ +From 60ad1bad25ea99c538b745ff95e6e0a877d37d1f Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:11 +0200 +Subject: [PATCH 13/16] qjson: Limit number of tokens in addition to total size + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-15-git-send-email-armbru@redhat.com> +Patchwork-id: 71476 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 13/15] qjson: Limit number of tokens in addition to total size +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +Commit 29c75dd "json-streamer: limit the maximum recursion depth and +maximum token count" attempts to guard against excessive heap usage by +limiting total token size (it says "token count", but that's a lie). + +Total token size is a rather imprecise predictor of heap usage: many +small tokens use more space than few large tokens with the same input +size, because there's a constant per-token overhead: 37 bytes on my +system. + +Tighten this up: limit the token count to 2Mi. Chosen to roughly +match the 64MiB total token size limit. + +Signed-off-by: Markus Armbruster +Reviewed-by: Eric Blake +Message-Id: <1448486613-17634-13-git-send-email-armbru@redhat.com> +(cherry picked from commit df649835fe48f635a93316fdefe96ced7189316e) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + qobject/json-streamer.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c +index e87230d..a4db4b8 100644 +--- a/qobject/json-streamer.c ++++ b/qobject/json-streamer.c +@@ -16,6 +16,7 @@ + #include "qapi/qmp/json-streamer.h" + + #define MAX_TOKEN_SIZE (64ULL << 20) ++#define MAX_TOKEN_COUNT (2ULL << 20) + #define MAX_NESTING (1ULL << 10) + + static void json_message_free_tokens(JSONMessageParser *parser) +@@ -68,6 +69,7 @@ static void json_message_process_token(JSONLexer *lexer, GString *input, + parser->bracket_count == 0)) { + goto out_emit; + } else if (parser->token_size > MAX_TOKEN_SIZE || ++ g_queue_get_length(parser->tokens) > MAX_TOKEN_COUNT || + parser->bracket_count + parser->brace_count > MAX_NESTING) { + /* Security consideration, we limit total memory allocated per object + * and the maximum recursion depth that a message can force. +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-Spell-out-some-silent-assumptions.patch b/SOURCES/kvm-qjson-Spell-out-some-silent-assumptions.patch new file mode 100644 index 0000000..6015054 --- /dev/null +++ b/SOURCES/kvm-qjson-Spell-out-some-silent-assumptions.patch @@ -0,0 +1,81 @@ +From c4c2e01b3fa861de40f809785a0643d56e2b311e Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:03 +0200 +Subject: [PATCH 05/16] qjson: Spell out some silent assumptions + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-7-git-send-email-armbru@redhat.com> +Patchwork-id: 71473 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 05/15] qjson: Spell out some silent assumptions +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +Signed-off-by: Markus Armbruster +Message-Id: <1448486613-17634-5-git-send-email-armbru@redhat.com> +Reviewed-by: Eric Blake +(cherry picked from commit b8d3b1da3cdbb02e180618d6be346c564723015d) +Signed-off-by: Markus Armbruster +Signed-off-by: Miroslav Rezanina +--- + include/qapi/qmp/json-lexer.h | 3 ++- + qobject/json-lexer.c | 7 ++++++- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/include/qapi/qmp/json-lexer.h b/include/qapi/qmp/json-lexer.h +index cdff046..61a143f 100644 +--- a/include/qapi/qmp/json-lexer.h ++++ b/include/qapi/qmp/json-lexer.h +@@ -18,7 +18,8 @@ + #include "qapi/qmp/qlist.h" + + typedef enum json_token_type { +- JSON_OPERATOR = 100, ++ JSON_MIN = 100, ++ JSON_OPERATOR = JSON_MIN, + JSON_INTEGER, + JSON_FLOAT, + JSON_KEYWORD, +diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c +index 440df60..f106ffb 100644 +--- a/qobject/json-lexer.c ++++ b/qobject/json-lexer.c +@@ -30,7 +30,7 @@ + */ + + enum json_lexer_state { +- IN_ERROR = 0, ++ IN_ERROR = 0, /* must really be 0, see json_lexer[] */ + IN_DQ_UCODE3, + IN_DQ_UCODE2, + IN_DQ_UCODE1, +@@ -62,6 +62,8 @@ enum json_lexer_state { + IN_START, + }; + ++QEMU_BUILD_BUG_ON((int)JSON_MIN <= (int)IN_START); ++ + #define TERMINAL(state) [0 ... 0x7F] = (state) + + /* Return whether TERMINAL is a terminal state and the transition to it +@@ -71,6 +73,8 @@ enum json_lexer_state { + (json_lexer[(old_state)][0] == (terminal)) + + static const uint8_t json_lexer[][256] = { ++ /* Relies on default initialization to IN_ERROR! */ ++ + /* double quote string */ + [IN_DQ_UCODE3] = { + ['0' ... '9'] = IN_DQ_STRING, +@@ -287,6 +291,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush) + } + + do { ++ assert(lexer->state <= ARRAY_SIZE(json_lexer)); + new_state = json_lexer[lexer->state][(uint8_t)ch]; + char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state); + if (char_consumed) { +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-replace-QString-in-JSONLexer-with-GString.patch b/SOURCES/kvm-qjson-replace-QString-in-JSONLexer-with-GString.patch new file mode 100644 index 0000000..02baa00 --- /dev/null +++ b/SOURCES/kvm-qjson-replace-QString-in-JSONLexer-with-GString.patch @@ -0,0 +1,195 @@ +From 39da81cf143ccc400263362a5319803063ad14cf Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:07 +0200 +Subject: [PATCH 09/16] qjson: replace QString in JSONLexer with GString + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-11-git-send-email-armbru@redhat.com> +Patchwork-id: 71480 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 09/15] qjson: replace QString in JSONLexer with GString +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Paolo Bonzini + +JSONLexer only needs a simple resizable buffer. json-streamer.c +can allocate memory for each token instead of relying on reference +counting of QStrings. + +Signed-off-by: Paolo Bonzini +Message-Id: <1448300659-23559-2-git-send-email-pbonzini@redhat.com> +[Straightforwardly rebased on my patches, checkpatch made happy] +Signed-off-by: Markus Armbruster +Reviewed-by: Eric Blake +(cherry picked from commit d2ca7c0b0d876cf0e219ae7a92252626b0913a28) +Signed-off-by: Markus Armbruster + +Signed-off-by: Miroslav Rezanina +--- + include/qapi/qmp/json-lexer.h | 8 ++++---- + include/qapi/qmp/json-streamer.h | 1 + + qobject/json-lexer.c | 22 ++++++++-------------- + qobject/json-streamer.c | 9 +++++---- + 4 files changed, 18 insertions(+), 22 deletions(-) + +diff --git a/include/qapi/qmp/json-lexer.h b/include/qapi/qmp/json-lexer.h +index f3e8dc7..cb456d5 100644 +--- a/include/qapi/qmp/json-lexer.h ++++ b/include/qapi/qmp/json-lexer.h +@@ -14,8 +14,7 @@ + #ifndef QEMU_JSON_LEXER_H + #define QEMU_JSON_LEXER_H + +-#include "qapi/qmp/qstring.h" +-#include "qapi/qmp/qlist.h" ++#include "glib-compat.h" + + typedef enum json_token_type { + JSON_MIN = 100, +@@ -36,13 +35,14 @@ typedef enum json_token_type { + + typedef struct JSONLexer JSONLexer; + +-typedef void (JSONLexerEmitter)(JSONLexer *, QString *, JSONTokenType, int x, int y); ++typedef void (JSONLexerEmitter)(JSONLexer *, GString *, ++ JSONTokenType, int x, int y); + + struct JSONLexer + { + JSONLexerEmitter *emit; + int state; +- QString *token; ++ GString *token; + int x, y; + }; + +diff --git a/include/qapi/qmp/json-streamer.h b/include/qapi/qmp/json-streamer.h +index 823f7d7..e901144 100644 +--- a/include/qapi/qmp/json-streamer.h ++++ b/include/qapi/qmp/json-streamer.h +@@ -14,6 +14,7 @@ + #ifndef QEMU_JSON_STREAMER_H + #define QEMU_JSON_STREAMER_H + ++#include + #include "qapi/qmp/qlist.h" + #include "qapi/qmp/json-lexer.h" + +diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c +index 1bfff02..b89e24f 100644 +--- a/qobject/json-lexer.c ++++ b/qobject/json-lexer.c +@@ -11,12 +11,9 @@ + * + */ + +-#include "qapi/qmp/qstring.h" +-#include "qapi/qmp/qlist.h" +-#include "qapi/qmp/qdict.h" +-#include "qapi/qmp/qint.h" + #include "qemu-common.h" + #include "qapi/qmp/json-lexer.h" ++#include + + #define MAX_TOKEN_SIZE (64ULL << 20) + +@@ -276,7 +273,7 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func) + { + lexer->emit = func; + lexer->state = IN_START; +- lexer->token = qstring_new(); ++ lexer->token = g_string_sized_new(3); + lexer->x = lexer->y = 0; + } + +@@ -295,7 +292,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush) + new_state = json_lexer[lexer->state][(uint8_t)ch]; + char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state); + if (char_consumed) { +- qstring_append_chr(lexer->token, ch); ++ g_string_append_c(lexer->token, ch); + } + + switch (new_state) { +@@ -313,8 +310,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush) + lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y); + /* fall through */ + case JSON_SKIP: +- QDECREF(lexer->token); +- lexer->token = qstring_new(); ++ g_string_truncate(lexer->token, 0); + new_state = IN_START; + break; + case IN_ERROR: +@@ -332,8 +328,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush) + * induce an error/flush state. + */ + lexer->emit(lexer, lexer->token, JSON_ERROR, lexer->x, lexer->y); +- QDECREF(lexer->token); +- lexer->token = qstring_new(); ++ g_string_truncate(lexer->token, 0); + new_state = IN_START; + lexer->state = new_state; + return 0; +@@ -346,10 +341,9 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush) + /* Do not let a single token grow to an arbitrarily large size, + * this is a security consideration. + */ +- if (lexer->token->length > MAX_TOKEN_SIZE) { ++ if (lexer->token->len > MAX_TOKEN_SIZE) { + lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y); +- QDECREF(lexer->token); +- lexer->token = qstring_new(); ++ g_string_truncate(lexer->token, 0); + lexer->state = IN_START; + } + +@@ -379,5 +373,5 @@ int json_lexer_flush(JSONLexer *lexer) + + void json_lexer_destroy(JSONLexer *lexer) + { +- QDECREF(lexer->token); ++ g_string_free(lexer->token, true); + } +diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c +index 4a161a1..7292f3a 100644 +--- a/qobject/json-streamer.c ++++ b/qobject/json-streamer.c +@@ -12,6 +12,7 @@ + */ + + #include "qapi/qmp/qlist.h" ++#include "qapi/qmp/qstring.h" + #include "qapi/qmp/qint.h" + #include "qapi/qmp/qdict.h" + #include "qemu-common.h" +@@ -21,7 +22,8 @@ + #define MAX_TOKEN_SIZE (64ULL << 20) + #define MAX_NESTING (1ULL << 10) + +-static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y) ++static void json_message_process_token(JSONLexer *lexer, GString *input, ++ JSONTokenType type, int x, int y) + { + JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer); + QDict *dict; +@@ -45,12 +47,11 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok + + dict = qdict_new(); + qdict_put(dict, "type", qint_from_int(type)); +- QINCREF(token); +- qdict_put(dict, "token", token); ++ qdict_put(dict, "token", qstring_from_str(input->str)); + qdict_put(dict, "x", qint_from_int(x)); + qdict_put(dict, "y", qint_from_int(y)); + +- parser->token_size += token->length; ++ parser->token_size += input->len; + + qlist_append(parser->tokens, dict); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-store-tokens-in-a-GQueue.patch b/SOURCES/kvm-qjson-store-tokens-in-a-GQueue.patch new file mode 100644 index 0000000..46ffff4 --- /dev/null +++ b/SOURCES/kvm-qjson-store-tokens-in-a-GQueue.patch @@ -0,0 +1,332 @@ +From 88ee76fed6344de6cede3bfbb3873423e9a90333 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:09 +0200 +Subject: [PATCH 11/16] qjson: store tokens in a GQueue + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-13-git-send-email-armbru@redhat.com> +Patchwork-id: 71478 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 11/15] qjson: store tokens in a GQueue +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Paolo Bonzini + +Even though we still have the "streamer" concept, the tokens can now +be deleted as they are read. While doing so convert from QList to +GQueue, since the next step will make tokens not a QObject and we +will have to do the conversion anyway. + +Signed-off-by: Paolo Bonzini +Message-Id: <1448300659-23559-4-git-send-email-pbonzini@redhat.com> +Signed-off-by: Markus Armbruster +Reviewed-by: Eric Blake +(cherry picked from commit 95385fe9ace7db156b924da6b6f5c9082b68ba68) +Signed-off-by: Miroslav Rezanina + +Conflicts: + monitor.c + +Trivial context difference because we lack a small cleanup part of the +(fairly invasive) series b821cbe..489653b. + +Signed-off-by: Markus Armbruster +--- + include/qapi/qmp/json-parser.h | 4 +-- + include/qapi/qmp/json-streamer.h | 8 ++--- + monitor.c | 2 +- + qga/main.c | 2 +- + qobject/json-parser.c | 65 +++++++++++++--------------------------- + qobject/json-streamer.c | 25 +++++++++------- + qobject/qjson.c | 2 +- + tests/libqtest.c | 2 +- + 8 files changed, 45 insertions(+), 65 deletions(-) + +diff --git a/include/qapi/qmp/json-parser.h b/include/qapi/qmp/json-parser.h +index 44d88f3..fea89f8 100644 +--- a/include/qapi/qmp/json-parser.h ++++ b/include/qapi/qmp/json-parser.h +@@ -18,7 +18,7 @@ + #include "qapi/qmp/qlist.h" + #include "qapi/error.h" + +-QObject *json_parser_parse(QList *tokens, va_list *ap); +-QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp); ++QObject *json_parser_parse(GQueue *tokens, va_list *ap); ++QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp); + + #endif +diff --git a/include/qapi/qmp/json-streamer.h b/include/qapi/qmp/json-streamer.h +index e901144..e9f2937 100644 +--- a/include/qapi/qmp/json-streamer.h ++++ b/include/qapi/qmp/json-streamer.h +@@ -15,21 +15,21 @@ + #define QEMU_JSON_STREAMER_H + + #include +-#include "qapi/qmp/qlist.h" ++#include "glib-compat.h" + #include "qapi/qmp/json-lexer.h" + + typedef struct JSONMessageParser + { +- void (*emit)(struct JSONMessageParser *parser, QList *tokens); ++ void (*emit)(struct JSONMessageParser *parser, GQueue *tokens); + JSONLexer lexer; + int brace_count; + int bracket_count; +- QList *tokens; ++ GQueue *tokens; + uint64_t token_size; + } JSONMessageParser; + + void json_message_parser_init(JSONMessageParser *parser, +- void (*func)(JSONMessageParser *, QList *)); ++ void (*func)(JSONMessageParser *, GQueue *)); + + int json_message_parser_feed(JSONMessageParser *parser, + const char *buffer, size_t size); +diff --git a/monitor.c b/monitor.c +index 33c5bc8..1b28ff3 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -4514,7 +4514,7 @@ static void qmp_call_cmd(Monitor *mon, const mon_cmd_t *cmd, + qobject_decref(data); + } + +-static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) ++static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) + { + int err; + QObject *obj; +diff --git a/qga/main.c b/qga/main.c +index 0e04e73..7e8f9a0 100644 +--- a/qga/main.c ++++ b/qga/main.c +@@ -569,7 +569,7 @@ static void process_command(GAState *s, QDict *req) + } + + /* handle requests/control events coming in over the channel */ +-static void process_event(JSONMessageParser *parser, QList *tokens) ++static void process_event(JSONMessageParser *parser, GQueue *tokens) + { + GAState *s = container_of(parser, GAState, parser); + QObject *obj; +diff --git a/qobject/json-parser.c b/qobject/json-parser.c +index b242fba..6e5e257 100644 +--- a/qobject/json-parser.c ++++ b/qobject/json-parser.c +@@ -27,11 +27,8 @@ + typedef struct JSONParserContext + { + Error *err; +- struct { +- QObject **buf; +- size_t pos; +- size_t count; +- } tokens; ++ QObject *current; ++ GQueue *buf; + } JSONParserContext; + + #define BUG_ON(cond) assert(!(cond)) +@@ -244,56 +241,34 @@ out: + return NULL; + } + ++/* Note: unless the token object returned by parser_context_peek_token ++ * or parser_context_pop_token is explicitly incref'd, it will be ++ * deleted as soon as parser_context_pop_token is called again. ++ */ + static QObject *parser_context_pop_token(JSONParserContext *ctxt) + { +- QObject *token; +- g_assert(ctxt->tokens.pos < ctxt->tokens.count); +- token = ctxt->tokens.buf[ctxt->tokens.pos]; +- ctxt->tokens.pos++; +- return token; ++ qobject_decref(ctxt->current); ++ assert(!g_queue_is_empty(ctxt->buf)); ++ ctxt->current = g_queue_pop_head(ctxt->buf); ++ return ctxt->current; + } + +-/* Note: parser_context_{peek|pop}_token do not increment the +- * token object's refcount. In both cases the references will continue +- * to be tracked and cleaned up in parser_context_free(), so do not +- * attempt to free the token object. +- */ + static QObject *parser_context_peek_token(JSONParserContext *ctxt) + { +- QObject *token; +- g_assert(ctxt->tokens.pos < ctxt->tokens.count); +- token = ctxt->tokens.buf[ctxt->tokens.pos]; +- return token; +-} +- +-static void tokens_append_from_iter(QObject *obj, void *opaque) +-{ +- JSONParserContext *ctxt = opaque; +- g_assert(ctxt->tokens.pos < ctxt->tokens.count); +- ctxt->tokens.buf[ctxt->tokens.pos++] = obj; +- qobject_incref(obj); ++ assert(!g_queue_is_empty(ctxt->buf)); ++ return g_queue_peek_head(ctxt->buf); + } + +-static JSONParserContext *parser_context_new(QList *tokens) ++static JSONParserContext *parser_context_new(GQueue *tokens) + { + JSONParserContext *ctxt; +- size_t count; + + if (!tokens) { + return NULL; + } + +- count = qlist_size(tokens); +- if (count == 0) { +- return NULL; +- } +- + ctxt = g_malloc0(sizeof(JSONParserContext)); +- ctxt->tokens.pos = 0; +- ctxt->tokens.count = count; +- ctxt->tokens.buf = g_malloc(count * sizeof(QObject *)); +- qlist_iter(tokens, tokens_append_from_iter, ctxt); +- ctxt->tokens.pos = 0; ++ ctxt->buf = tokens; + + return ctxt; + } +@@ -301,12 +276,12 @@ static JSONParserContext *parser_context_new(QList *tokens) + /* to support error propagation, ctxt->err must be freed separately */ + static void parser_context_free(JSONParserContext *ctxt) + { +- int i; + if (ctxt) { +- for (i = 0; i < ctxt->tokens.count; i++) { +- qobject_decref(ctxt->tokens.buf[i]); ++ while (!g_queue_is_empty(ctxt->buf)) { ++ parser_context_pop_token(ctxt); + } +- g_free(ctxt->tokens.buf); ++ qobject_decref(ctxt->current); ++ g_queue_free(ctxt->buf); + g_free(ctxt); + } + } +@@ -597,12 +572,12 @@ static QObject *parse_value(JSONParserContext *ctxt, va_list *ap) + } + } + +-QObject *json_parser_parse(QList *tokens, va_list *ap) ++QObject *json_parser_parse(GQueue *tokens, va_list *ap) + { + return json_parser_parse_err(tokens, ap, NULL); + } + +-QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp) ++QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp) + { + JSONParserContext *ctxt = parser_context_new(tokens); + QObject *result; +diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c +index 7292f3a..f7a3e78 100644 +--- a/qobject/json-streamer.c ++++ b/qobject/json-streamer.c +@@ -22,6 +22,14 @@ + #define MAX_TOKEN_SIZE (64ULL << 20) + #define MAX_NESTING (1ULL << 10) + ++static void json_message_free_tokens(JSONMessageParser *parser) ++{ ++ if (parser->tokens) { ++ g_queue_free(parser->tokens); ++ parser->tokens = NULL; ++ } ++} ++ + static void json_message_process_token(JSONLexer *lexer, GString *input, + JSONTokenType type, int x, int y) + { +@@ -53,7 +61,7 @@ static void json_message_process_token(JSONLexer *lexer, GString *input, + + parser->token_size += input->len; + +- qlist_append(parser->tokens, dict); ++ g_queue_push_tail(parser->tokens, dict); + + if (type == JSON_ERROR) { + goto out_emit_bad; +@@ -77,27 +85,24 @@ out_emit_bad: + * Clear out token list and tell the parser to emit an error + * indication by passing it a NULL list + */ +- QDECREF(parser->tokens); +- parser->tokens = NULL; ++ json_message_free_tokens(parser); + out_emit: + /* send current list of tokens to parser and reset tokenizer */ + parser->brace_count = 0; + parser->bracket_count = 0; ++ /* parser->emit takes ownership of parser->tokens. */ + parser->emit(parser, parser->tokens); +- if (parser->tokens) { +- QDECREF(parser->tokens); +- } +- parser->tokens = qlist_new(); ++ parser->tokens = g_queue_new(); + parser->token_size = 0; + } + + void json_message_parser_init(JSONMessageParser *parser, +- void (*func)(JSONMessageParser *, QList *)) ++ void (*func)(JSONMessageParser *, GQueue *)) + { + parser->emit = func; + parser->brace_count = 0; + parser->bracket_count = 0; +- parser->tokens = qlist_new(); ++ parser->tokens = g_queue_new(); + parser->token_size = 0; + + json_lexer_init(&parser->lexer, json_message_process_token); +@@ -117,5 +122,5 @@ int json_message_parser_flush(JSONMessageParser *parser) + void json_message_parser_destroy(JSONMessageParser *parser) + { + json_lexer_destroy(&parser->lexer); +- QDECREF(parser->tokens); ++ json_message_free_tokens(parser); + } +diff --git a/qobject/qjson.c b/qobject/qjson.c +index 6cf2511..fdc274a 100644 +--- a/qobject/qjson.c ++++ b/qobject/qjson.c +@@ -28,7 +28,7 @@ typedef struct JSONParsingState + QObject *result; + } JSONParsingState; + +-static void parse_json(JSONMessageParser *parser, QList *tokens) ++static void parse_json(JSONMessageParser *parser, GQueue *tokens) + { + JSONParsingState *s = container_of(parser, JSONParsingState, parser); + s->result = json_parser_parse(tokens, s->ap); +diff --git a/tests/libqtest.c b/tests/libqtest.c +index 359d571..69b7cd6 100644 +--- a/tests/libqtest.c ++++ b/tests/libqtest.c +@@ -299,7 +299,7 @@ typedef struct { + QDict *response; + } QMPResponseParser; + +-static void qmp_response(JSONMessageParser *parser, QList *tokens) ++static void qmp_response(JSONMessageParser *parser, GQueue *tokens) + { + QMPResponseParser *qmp = container_of(parser, QMPResponseParser, parser); + QObject *obj; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qjson-surprise-allocating-6-QObjects-per-token-is-ex.patch b/SOURCES/kvm-qjson-surprise-allocating-6-QObjects-per-token-is-ex.patch new file mode 100644 index 0000000..fb4fd05 --- /dev/null +++ b/SOURCES/kvm-qjson-surprise-allocating-6-QObjects-per-token-is-ex.patch @@ -0,0 +1,412 @@ +From 7bef5fab7d59aa9a6a1eb6ea747ba04811bc01e2 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Wed, 27 Jul 2016 07:35:10 +0200 +Subject: [PATCH 12/16] qjson: surprise, allocating 6 QObjects per token is + expensive + +RH-Author: Markus Armbruster +Message-id: <1469604913-12442-14-git-send-email-armbru@redhat.com> +Patchwork-id: 71475 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 12/15] qjson: surprise, allocating 6 QObjects per token is expensive +Bugzilla: 1276036 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Paolo Bonzini + +Replace the contents of the tokens GQueue with a simple struct. This cuts +the amount of memory allocated by tests/check-qjson from ~500MB to ~20MB, +and the execution time from 600ms to 80ms on my laptop. Still a lot (some +could be saved by using an intrusive list, such as QSIMPLEQ, instead of +the GQueue), but the savings are already massive and the right thing to +do would probably be to get rid of json-streamer completely. + +Signed-off-by: Paolo Bonzini +Message-Id: <1448300659-23559-5-git-send-email-pbonzini@redhat.com> +[Straightforwardly rebased on my patches] +Signed-off-by: Markus Armbruster +Reviewed-by: Eric Blake +(cherry picked from commit 9bada8971173345ceb37ed1a47b00a01a4dd48cf) + +Signed-off-by: Miroslav Rezanina + +Conflicts: + qobject/json-parser.c + +Straighforward conflicts because lacking commit fc48ffc "qobject: Use +'bool' for qbool", we still use qbool_from_int(), and we lack commit +e549e71 "json-parser: Accept 'null' in QMP". + +Signed-off-by: Markus Armbruster +--- + include/qapi/qmp/json-streamer.h | 7 +++ + qobject/json-parser.c | 113 ++++++++++++++++----------------------- + qobject/json-streamer.c | 19 +++---- + 3 files changed, 62 insertions(+), 77 deletions(-) + +diff --git a/include/qapi/qmp/json-streamer.h b/include/qapi/qmp/json-streamer.h +index e9f2937..09b3d3e 100644 +--- a/include/qapi/qmp/json-streamer.h ++++ b/include/qapi/qmp/json-streamer.h +@@ -18,6 +18,13 @@ + #include "glib-compat.h" + #include "qapi/qmp/json-lexer.h" + ++typedef struct JSONToken { ++ int type; ++ int x; ++ int y; ++ char str[]; ++} JSONToken; ++ + typedef struct JSONMessageParser + { + void (*emit)(struct JSONMessageParser *parser, GQueue *tokens); +diff --git a/qobject/json-parser.c b/qobject/json-parser.c +index 6e5e257..944e1a1 100644 +--- a/qobject/json-parser.c ++++ b/qobject/json-parser.c +@@ -23,11 +23,12 @@ + #include "qapi/qmp/json-parser.h" + #include "qapi/qmp/json-lexer.h" + #include "qapi/qmp/qerror.h" ++#include "qapi/qmp/json-streamer.h" + + typedef struct JSONParserContext + { + Error *err; +- QObject *current; ++ JSONToken *current; + GQueue *buf; + } JSONParserContext; + +@@ -45,27 +46,10 @@ typedef struct JSONParserContext + static QObject *parse_value(JSONParserContext *ctxt, va_list *ap); + + /** +- * Token manipulators +- * +- * tokens are dictionaries that contain a type, a string value, and geometry information +- * about a token identified by the lexer. These are routines that make working with +- * these objects a bit easier. +- */ +-static const char *token_get_value(QObject *obj) +-{ +- return qdict_get_str(qobject_to_qdict(obj), "token"); +-} +- +-static JSONTokenType token_get_type(QObject *obj) +-{ +- return qdict_get_int(qobject_to_qdict(obj), "type"); +-} +- +-/** + * Error handler + */ + static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt, +- QObject *token, const char *msg, ...) ++ JSONToken *token, const char *msg, ...) + { + va_list ap; + char message[1024]; +@@ -143,9 +127,10 @@ static int hex2decimal(char ch) + * \t + * \u four-hex-digits + */ +-static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token) ++static QString *qstring_from_escaped_str(JSONParserContext *ctxt, ++ JSONToken *token) + { +- const char *ptr = token_get_value(token); ++ const char *ptr = token->str; + QString *str; + int double_quote = 1; + +@@ -241,19 +226,19 @@ out: + return NULL; + } + +-/* Note: unless the token object returned by parser_context_peek_token +- * or parser_context_pop_token is explicitly incref'd, it will be +- * deleted as soon as parser_context_pop_token is called again. ++/* Note: the token object returned by parser_context_peek_token or ++ * parser_context_pop_token is deleted as soon as parser_context_pop_token ++ * is called again. + */ +-static QObject *parser_context_pop_token(JSONParserContext *ctxt) ++static JSONToken *parser_context_pop_token(JSONParserContext *ctxt) + { +- qobject_decref(ctxt->current); ++ g_free(ctxt->current); + assert(!g_queue_is_empty(ctxt->buf)); + ctxt->current = g_queue_pop_head(ctxt->buf); + return ctxt->current; + } + +-static QObject *parser_context_peek_token(JSONParserContext *ctxt) ++static JSONToken *parser_context_peek_token(JSONParserContext *ctxt) + { + assert(!g_queue_is_empty(ctxt->buf)); + return g_queue_peek_head(ctxt->buf); +@@ -280,7 +265,7 @@ static void parser_context_free(JSONParserContext *ctxt) + while (!g_queue_is_empty(ctxt->buf)) { + parser_context_pop_token(ctxt); + } +- qobject_decref(ctxt->current); ++ g_free(ctxt->current); + g_queue_free(ctxt->buf); + g_free(ctxt); + } +@@ -291,7 +276,8 @@ static void parser_context_free(JSONParserContext *ctxt) + */ + static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap) + { +- QObject *key = NULL, *token = NULL, *value, *peek; ++ QObject *key = NULL, *value; ++ JSONToken *peek, *token; + + peek = parser_context_peek_token(ctxt); + if (peek == NULL) { +@@ -311,7 +297,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap) + goto out; + } + +- if (token_get_type(token) != JSON_COLON) { ++ if (token->type != JSON_COLON) { + parse_error(ctxt, token, "missing : in object pair"); + goto out; + } +@@ -337,10 +323,10 @@ out: + static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + { + QDict *dict = NULL; +- QObject *token, *peek; ++ JSONToken *token, *peek; + + token = parser_context_pop_token(ctxt); +- assert(token && token_get_type(token) == JSON_LCURLY); ++ assert(token && token->type == JSON_LCURLY); + + dict = qdict_new(); + +@@ -350,7 +336,7 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- if (token_get_type(peek) != JSON_RCURLY) { ++ if (peek->type != JSON_RCURLY) { + if (parse_pair(ctxt, dict, ap) == -1) { + goto out; + } +@@ -361,8 +347,8 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- while (token_get_type(token) != JSON_RCURLY) { +- if (token_get_type(token) != JSON_COMMA) { ++ while (token->type != JSON_RCURLY) { ++ if (token->type != JSON_COMMA) { + parse_error(ctxt, token, "expected separator in dict"); + goto out; + } +@@ -391,10 +377,10 @@ out: + static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + { + QList *list = NULL; +- QObject *token, *peek; ++ JSONToken *token, *peek; + + token = parser_context_pop_token(ctxt); +- assert(token && token_get_type(token) == JSON_LSQUARE); ++ assert(token && token->type == JSON_LSQUARE); + + list = qlist_new(); + +@@ -404,7 +390,7 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- if (token_get_type(peek) != JSON_RSQUARE) { ++ if (peek->type != JSON_RSQUARE) { + QObject *obj; + + obj = parse_value(ctxt, ap); +@@ -421,8 +407,8 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) + goto out; + } + +- while (token_get_type(token) != JSON_RSQUARE) { +- if (token_get_type(token) != JSON_COMMA) { ++ while (token->type != JSON_RSQUARE) { ++ if (token->type != JSON_COMMA) { + parse_error(ctxt, token, "expected separator in list"); + goto out; + } +@@ -454,49 +440,45 @@ out: + + static QObject *parse_keyword(JSONParserContext *ctxt) + { +- QObject *token; +- const char *val; ++ JSONToken *token; + + token = parser_context_pop_token(ctxt); +- assert(token && token_get_type(token) == JSON_KEYWORD); +- val = token_get_value(token); ++ assert(token && token->type == JSON_KEYWORD); + +- if (!strcmp(val, "true")) { ++ if (!strcmp(token->str, "true")) { + return QOBJECT(qbool_from_int(true)); +- } else if (!strcmp(val, "false")) { ++ } else if (!strcmp(token->str, "false")) { + return QOBJECT(qbool_from_int(false)); + } +- parse_error(ctxt, token, "invalid keyword '%s'", val); ++ parse_error(ctxt, token, "invalid keyword '%s'", token->str); + return NULL; + } + + static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap) + { +- QObject *token; +- const char *val; ++ JSONToken *token; + + if (ap == NULL) { + return NULL; + } + + token = parser_context_pop_token(ctxt); +- assert(token && token_get_type(token) == JSON_ESCAPE); +- val = token_get_value(token); ++ assert(token && token->type == JSON_ESCAPE); + +- if (!strcmp(val, "%p")) { ++ if (!strcmp(token->str, "%p")) { + return va_arg(*ap, QObject *); +- } else if (!strcmp(val, "%i")) { ++ } else if (!strcmp(token->str, "%i")) { + return QOBJECT(qbool_from_int(va_arg(*ap, int))); +- } else if (!strcmp(val, "%d")) { ++ } else if (!strcmp(token->str, "%d")) { + return QOBJECT(qint_from_int(va_arg(*ap, int))); +- } else if (!strcmp(val, "%ld")) { ++ } else if (!strcmp(token->str, "%ld")) { + return QOBJECT(qint_from_int(va_arg(*ap, long))); +- } else if (!strcmp(val, "%lld") || +- !strcmp(val, "%I64d")) { ++ } else if (!strcmp(token->str, "%lld") || ++ !strcmp(token->str, "%I64d")) { + return QOBJECT(qint_from_int(va_arg(*ap, long long))); +- } else if (!strcmp(val, "%s")) { ++ } else if (!strcmp(token->str, "%s")) { + return QOBJECT(qstring_from_str(va_arg(*ap, const char *))); +- } else if (!strcmp(val, "%f")) { ++ } else if (!strcmp(token->str, "%f")) { + return QOBJECT(qfloat_from_double(va_arg(*ap, double))); + } + return NULL; +@@ -504,12 +486,12 @@ static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap) + + static QObject *parse_literal(JSONParserContext *ctxt) + { +- QObject *token; ++ JSONToken *token; + + token = parser_context_pop_token(ctxt); + assert(token); + +- switch (token_get_type(token)) { ++ switch (token->type) { + case JSON_STRING: + return QOBJECT(qstring_from_escaped_str(ctxt, token)); + case JSON_INTEGER: { +@@ -528,7 +510,7 @@ static QObject *parse_literal(JSONParserContext *ctxt) + int64_t value; + + errno = 0; /* strtoll doesn't set errno on success */ +- value = strtoll(token_get_value(token), NULL, 10); ++ value = strtoll(token->str, NULL, 10); + if (errno != ERANGE) { + return QOBJECT(qint_from_int(value)); + } +@@ -536,8 +518,7 @@ static QObject *parse_literal(JSONParserContext *ctxt) + } + case JSON_FLOAT: + /* FIXME dependent on locale */ +- return QOBJECT(qfloat_from_double(strtod(token_get_value(token), +- NULL))); ++ return QOBJECT(qfloat_from_double(strtod(token->str, NULL))); + default: + abort(); + } +@@ -545,7 +526,7 @@ static QObject *parse_literal(JSONParserContext *ctxt) + + static QObject *parse_value(JSONParserContext *ctxt, va_list *ap) + { +- QObject *token; ++ JSONToken *token; + + token = parser_context_peek_token(ctxt); + if (token == NULL) { +@@ -553,7 +534,7 @@ static QObject *parse_value(JSONParserContext *ctxt, va_list *ap) + return NULL; + } + +- switch (token_get_type(token)) { ++ switch (token->type) { + case JSON_LCURLY: + return parse_object(ctxt, ap); + case JSON_LSQUARE: +diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c +index f7a3e78..e87230d 100644 +--- a/qobject/json-streamer.c ++++ b/qobject/json-streamer.c +@@ -11,10 +11,6 @@ + * + */ + +-#include "qapi/qmp/qlist.h" +-#include "qapi/qmp/qstring.h" +-#include "qapi/qmp/qint.h" +-#include "qapi/qmp/qdict.h" + #include "qemu-common.h" + #include "qapi/qmp/json-lexer.h" + #include "qapi/qmp/json-streamer.h" +@@ -34,7 +30,7 @@ static void json_message_process_token(JSONLexer *lexer, GString *input, + JSONTokenType type, int x, int y) + { + JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer); +- QDict *dict; ++ JSONToken *token; + + switch (type) { + case JSON_LCURLY: +@@ -53,15 +49,16 @@ static void json_message_process_token(JSONLexer *lexer, GString *input, + break; + } + +- dict = qdict_new(); +- qdict_put(dict, "type", qint_from_int(type)); +- qdict_put(dict, "token", qstring_from_str(input->str)); +- qdict_put(dict, "x", qint_from_int(x)); +- qdict_put(dict, "y", qint_from_int(y)); ++ token = g_malloc(sizeof(JSONToken) + input->len + 1); ++ token->type = type; ++ memcpy(token->str, input->str, input->len); ++ token->str[input->len] = 0; ++ token->x = x; ++ token->y = y; + + parser->token_size += input->len; + +- g_queue_push_tail(parser->tokens, dict); ++ g_queue_push_tail(parser->tokens, token); + + if (type == JSON_ERROR) { + goto out_emit_bad; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qxl-Fix-new-function-name-for-spice-server-library.patch b/SOURCES/kvm-qxl-Fix-new-function-name-for-spice-server-library.patch new file mode 100644 index 0000000..418fa4e --- /dev/null +++ b/SOURCES/kvm-qxl-Fix-new-function-name-for-spice-server-library.patch @@ -0,0 +1,57 @@ +From ac053d6013f7fab73f66db60462c388bea21b714 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: +References: +From: Gerd Hoffmann +Date: Fri, 13 May 2016 16:09:29 -0400 +Subject: [CHANGE 2/3] qxl: Fix new function name for spice-server library +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +To: rhvirt-patches@redhat.com, + jen@redhat.com + +RH-Author: Gerd Hoffmann +Message-id: <1463155769-32352-3-git-send-email-kraxel@redhat.com> +Patchwork-id: 70403 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 2/2] qxl: Fix new function name for spice-server library +Bugzilla: 1283198 +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Thomas Huth + +From: Frediano Ziglio + +The new spice-server function to limit the number of monitors (0.12.6) +changed while development from spice_qxl_set_monitors_config_limit to +spice_qxl_max_monitors (accepted upstream). +By mistake I post patch with former name. +This patch fix the function name. + +Signed-off-by: Frediano Ziglio +Acked-by: Christophe Fergeau +Acked-by: Martin Kletzander +Signed-off-by: Marc-André Lureau +(cherry picked from commit a52b2cbf218d52f9e357961acb271a98a2bdff71) +Signed-off-by: Jeff E. Nelson +--- + hw/display/qxl.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index 1f6a303..748dfce 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -268,8 +268,7 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) + } else { + #if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ + if (qxl->max_outputs) { +- spice_qxl_set_monitors_config_limit(&qxl->ssd.qxl, +- qxl->max_outputs); ++ spice_qxl_set_max_monitors(&qxl->ssd.qxl, qxl->max_outputs); + } + #endif + qxl->guest_monitors_config = qxl->ram->monitors_config; +-- +2.5.5 + diff --git a/SOURCES/kvm-qxl-allow-to-specify-head-limit-to-qxl-driver.patch b/SOURCES/kvm-qxl-allow-to-specify-head-limit-to-qxl-driver.patch new file mode 100644 index 0000000..bc50ebd --- /dev/null +++ b/SOURCES/kvm-qxl-allow-to-specify-head-limit-to-qxl-driver.patch @@ -0,0 +1,120 @@ +From c7936395ecf322b3de37662c7c6b772e36866cc7 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Gerd Hoffmann +Date: Fri, 13 May 2016 16:09:28 -0400 +Subject: [CHANGE 1/3] qxl: allow to specify head limit to qxl driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +To: rhvirt-patches@redhat.com, + jen@redhat.com + +RH-Author: Gerd Hoffmann +Message-id: <1463155769-32352-2-git-send-email-kraxel@redhat.com> +Patchwork-id: 70404 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/2] qxl: allow to specify head limit to qxl driver +Bugzilla: 1283198 +RH-Acked-by: Marc-André Lureau +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Thomas Huth + +From: Frediano Ziglio + +This patch allow to limit number of heads using qxl driver. By default +qxl driver is not limited on any kind on head use so can decide to use +as much heads. + +libvirt has this as a video card parameter (actually set to 1 but not +used). This parameter will allow to limit setting a use can do (which +could be confusing). + +Signed-off-by: Frediano Ziglio +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 567161fdd47aeb6987e700702f6bbfef04ae0236) +Signed-off-by: Jeff E. Nelson +--- + hw/display/qxl.c | 26 +++++++++++++++++++++----- + hw/display/qxl.h | 3 +++ + 2 files changed, 24 insertions(+), 5 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index f11210c..1f6a303 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -266,6 +266,12 @@ static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) + QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, + 0)); + } else { ++#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ ++ if (qxl->max_outputs) { ++ spice_qxl_set_monitors_config_limit(&qxl->ssd.qxl, ++ qxl->max_outputs); ++ } ++#endif + qxl->guest_monitors_config = qxl->ram->monitors_config; + spice_qxl_monitors_config_async(&qxl->ssd.qxl, + qxl->ram->monitors_config, +@@ -991,6 +997,7 @@ static int interface_client_monitors_config(QXLInstance *sin, + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar); + int i; ++ unsigned max_outputs = ARRAY_SIZE(rom->client_monitors_config.heads); + + if (qxl->revision < 4) { + trace_qxl_client_monitors_config_unsupported_by_device(qxl->id, +@@ -1013,17 +1020,23 @@ static int interface_client_monitors_config(QXLInstance *sin, + if (!monitors_config) { + return 1; + } ++ ++#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ ++ /* limit number of outputs based on setting limit */ ++ if (qxl->max_outputs && qxl->max_outputs <= max_outputs) { ++ max_outputs = qxl->max_outputs; ++ } ++#endif ++ + memset(&rom->client_monitors_config, 0, + sizeof(rom->client_monitors_config)); + rom->client_monitors_config.count = monitors_config->num_of_monitors; + /* monitors_config->flags ignored */ +- if (rom->client_monitors_config.count >= +- ARRAY_SIZE(rom->client_monitors_config.heads)) { ++ if (rom->client_monitors_config.count >= max_outputs) { + trace_qxl_client_monitors_config_capped(qxl->id, + monitors_config->num_of_monitors, +- ARRAY_SIZE(rom->client_monitors_config.heads)); +- rom->client_monitors_config.count = +- ARRAY_SIZE(rom->client_monitors_config.heads); ++ max_outputs); ++ rom->client_monitors_config.count = max_outputs; + } + for (i = 0 ; i < rom->client_monitors_config.count ; ++i) { + VDAgentMonConfig *monitor = &monitors_config->monitors[i]; +@@ -2294,6 +2307,9 @@ static Property qxl_properties[] = { + DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1), + DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16), + DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024), ++#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ ++ DEFINE_PROP_UINT16("max_outputs", PCIQXLDevice, max_outputs, 0), ++#endif + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/hw/display/qxl.h b/hw/display/qxl.h +index 5da33e2..5247ce9 100644 +--- a/hw/display/qxl.h ++++ b/hw/display/qxl.h +@@ -95,6 +95,9 @@ typedef struct PCIQXLDevice { + QXLModes *modes; + uint32_t rom_size; + MemoryRegion rom_bar; ++#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */ ++ uint16_t max_outputs; ++#endif + + /* vram pci bar */ + uint32_t vram_size; +-- +2.5.5 + diff --git a/SOURCES/kvm-qxl-factor-out-qxl_get_check_slot_offset.patch b/SOURCES/kvm-qxl-factor-out-qxl_get_check_slot_offset.patch new file mode 100644 index 0000000..7ba85fe --- /dev/null +++ b/SOURCES/kvm-qxl-factor-out-qxl_get_check_slot_offset.patch @@ -0,0 +1,108 @@ +From 24a604e857d2797c3da9852bcbea75f2f9e6961c Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 22 Jul 2016 09:34:38 +0200 +Subject: [PATCH 1/4] qxl: factor out qxl_get_check_slot_offset + +RH-Author: Gerd Hoffmann +Message-id: <1469180081-28522-2-git-send-email-kraxel@redhat.com> +Patchwork-id: 71317 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 1/4] qxl: factor out qxl_get_check_slot_offset +Bugzilla: 1355730 +RH-Acked-by: Laurent Vivier +RH-Acked-by: John Snow +RH-Acked-by: Laszlo Ersek + +New helper function which translates a qxl physical address into +memory slot and offset. Also applies sanity checks. Factored out +from qxl_phys2virt. No functional change. + +Signed-off-by: Gerd Hoffmann +Message-id: 1466597244-5938-1-git-send-email-kraxel@redhat.com +(cherry picked from commit 726bdf653aca9b87e28c9a56dd94c4667ddfacbc) +Signed-off-by: Miroslav Rezanina +--- + hw/display/qxl.c | 59 ++++++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 38 insertions(+), 21 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index 748dfce..5e1ecd8 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -1326,36 +1326,53 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) + } + + /* can be also called from spice server thread context */ +-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) ++static bool qxl_get_check_slot_offset(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, ++ uint32_t *s, uint64_t *o) + { + uint64_t phys = le64_to_cpu(pqxl); + uint32_t slot = (phys >> (64 - 8)) & 0xff; + uint64_t offset = phys & 0xffffffffffff; + +- switch (group_id) { +- case MEMSLOT_GROUP_HOST: +- return (void *)(intptr_t)offset; +- case MEMSLOT_GROUP_GUEST: +- if (slot >= NUM_MEMSLOTS) { +- qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot, +- NUM_MEMSLOTS); +- return NULL; +- } +- if (!qxl->guest_slots[slot].active) { +- qxl_set_guest_bug(qxl, "inactive slot %d\n", slot); +- return NULL; +- } +- if (offset < qxl->guest_slots[slot].delta) { +- qxl_set_guest_bug(qxl, ++ if (slot >= NUM_MEMSLOTS) { ++ qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot, ++ NUM_MEMSLOTS); ++ return false; ++ } ++ if (!qxl->guest_slots[slot].active) { ++ qxl_set_guest_bug(qxl, "inactive slot %d\n", slot); ++ return false; ++ } ++ if (offset < qxl->guest_slots[slot].delta) { ++ qxl_set_guest_bug(qxl, + "slot %d offset %"PRIu64" < delta %"PRIu64"\n", + slot, offset, qxl->guest_slots[slot].delta); +- return NULL; +- } +- offset -= qxl->guest_slots[slot].delta; +- if (offset > qxl->guest_slots[slot].size) { +- qxl_set_guest_bug(qxl, ++ return false; ++ } ++ offset -= qxl->guest_slots[slot].delta; ++ if (offset > qxl->guest_slots[slot].size) { ++ qxl_set_guest_bug(qxl, + "slot %d offset %"PRIu64" > size %"PRIu64"\n", + slot, offset, qxl->guest_slots[slot].size); ++ return false; ++ } ++ ++ *s = slot; ++ *o = offset; ++ return true; ++} ++ ++/* can be also called from spice server thread context */ ++void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) ++{ ++ uint64_t offset; ++ uint32_t slot; ++ ++ switch (group_id) { ++ case MEMSLOT_GROUP_HOST: ++ offset = le64_to_cpu(pqxl) & 0xffffffffffff; ++ return (void *)(intptr_t)offset; ++ case MEMSLOT_GROUP_GUEST: ++ if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset)) { + return NULL; + } + return qxl->guest_slots[slot].ptr + offset; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qxl-fix-qxl_set_dirty-call-in-qxl_dirty_one_surface.patch b/SOURCES/kvm-qxl-fix-qxl_set_dirty-call-in-qxl_dirty_one_surface.patch new file mode 100644 index 0000000..99b1593 --- /dev/null +++ b/SOURCES/kvm-qxl-fix-qxl_set_dirty-call-in-qxl_dirty_one_surface.patch @@ -0,0 +1,79 @@ +From e7fe5cf70d63552006e8c9eb660db95279f2a3a9 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 22 Jul 2016 09:34:41 +0200 +Subject: [PATCH 4/4] qxl: fix qxl_set_dirty call in qxl_dirty_one_surface + +RH-Author: Gerd Hoffmann +Message-id: <1469180081-28522-5-git-send-email-kraxel@redhat.com> +Patchwork-id: 71316 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 4/4] qxl: fix qxl_set_dirty call in qxl_dirty_one_surface +Bugzilla: 1355730 +RH-Acked-by: Laurent Vivier +RH-Acked-by: John Snow +RH-Acked-by: Laszlo Ersek + +qxl_set_dirty() expects start and end as range specification. +qxl_dirty_one_surface passes 'size' instead of 'offset + size' as end +parameter. Fix that. Also use uint64_t everywhere while being at it. + +Bug was added by "e25139b qxl: set only off-screen surfaces dirty instead +of the whole vram" and carried forward unnoticed by "5cdc402 qxl: fix +surface migration". + +Reported-by: Dr. David Alan Gilbert +Signed-off-by: Gerd Hoffmann +Reviewed-by: Dr. David Alan Gilbert +Message-id: 1468413187-22071-1-git-send-email-kraxel@redhat.com +(cherry picked from commit e0127d2eec9cd5676ea9f3c47c2a7579a02c0466) +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/display/trace-events +--- + hw/display/qxl.c | 11 ++++++----- + trace-events | 2 +- + 2 files changed, 7 insertions(+), 6 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index d65c830..f762439 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -1825,16 +1825,17 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) + static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, + uint32_t height, int32_t stride) + { +- uint64_t offset; +- uint32_t slot, size; ++ uint64_t offset, size; ++ uint32_t slot; + bool rc; + + rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset); + assert(rc == true); +- size = height * abs(stride); +- trace_qxl_surfaces_dirty(qxl->id, (int)offset, size); ++ size = (uint64_t)height * abs(stride); ++ trace_qxl_surfaces_dirty(qxl->id, offset, size); + qxl_set_dirty(qxl->guest_slots[slot].mr, +- qxl->guest_slots[slot].offset + offset, size); ++ qxl->guest_slots[slot].offset + offset, ++ qxl->guest_slots[slot].offset + offset + size); + } + + static void qxl_dirty_surfaces(PCIQXLDevice *qxl) +diff --git a/trace-events b/trace-events +index 4da84b2..af5147a 100644 +--- a/trace-events ++++ b/trace-events +@@ -1078,7 +1078,7 @@ qxl_spice_reset_image_cache(int qid) "%d" + qxl_spice_reset_memslots(int qid) "%d" + qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" + qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" +-qxl_surfaces_dirty(int qid, int offset, int size) "%d offset=%d size=%d" ++qxl_surfaces_dirty(int qid, uint64_t offset, uint64_t size) "%d offset=0x%"PRIx64" size=0x%"PRIx64 + qxl_send_events(int qid, uint32_t events) "%d %d" + qxl_send_events_vm_stopped(int qid, uint32_t events) "%d %d" + qxl_set_guest_bug(int qid) "%d" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qxl-fix-surface-migration.patch b/SOURCES/kvm-qxl-fix-surface-migration.patch new file mode 100644 index 0000000..f164825 --- /dev/null +++ b/SOURCES/kvm-qxl-fix-surface-migration.patch @@ -0,0 +1,124 @@ +From 13bf417cd4063f5db2f0a79265745481d4c69d0d Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 22 Jul 2016 09:34:40 +0200 +Subject: [PATCH 3/4] qxl: fix surface migration + +RH-Author: Gerd Hoffmann +Message-id: <1469180081-28522-4-git-send-email-kraxel@redhat.com> +Patchwork-id: 71315 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 3/4] qxl: fix surface migration +Bugzilla: 1355730 +RH-Acked-by: Laurent Vivier +RH-Acked-by: John Snow +RH-Acked-by: Laszlo Ersek + +Create a helper function qxl_dirty_one_surface() to mark a single qxl +surface as dirty. Use the new qxl_get_check_slot_offset function and +lookup the memory region from the slot instead of assuming the surface +is stored in vram. + +Use the new helper function in qxl_dirty_surfaces, for both primary and +off-screen surfaces. For off-screen surfaces this is no functional +change. For primary surfaces this will dirty only the memory actually +used instead of the whole surface0 region. It will also work correctly +in case the guest places the primary surface in vram instead of the +surface0 region (linux kms driver does that). + +https://bugzilla.redhat.com/show_bug.cgi?id=1235732 + +Signed-off-by: Gerd Hoffmann +Message-id: 1466597244-5938-3-git-send-email-kraxel@redhat.com +(cherry picked from commit 1331eab216c9dc4e50a48a34d14926b31a7fd611) +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/display/trace-events +--- + hw/display/qxl.c | 37 +++++++++++++++++++++---------------- + trace-events | 2 +- + 2 files changed, 22 insertions(+), 17 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index de5770e..d65c830 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -1822,9 +1822,23 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) + } + } + ++static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, ++ uint32_t height, int32_t stride) ++{ ++ uint64_t offset; ++ uint32_t slot, size; ++ bool rc; ++ ++ rc = qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset); ++ assert(rc == true); ++ size = height * abs(stride); ++ trace_qxl_surfaces_dirty(qxl->id, (int)offset, size); ++ qxl_set_dirty(qxl->guest_slots[slot].mr, ++ qxl->guest_slots[slot].offset + offset, size); ++} ++ + static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + { +- uintptr_t vram_start; + int i; + + if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) { +@@ -1832,16 +1846,13 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + } + + /* dirty the primary surface */ +- qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, +- qxl->shadow_rom.surface0_area_size); +- +- vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); ++ qxl_dirty_one_surface(qxl, qxl->guest_primary.surface.mem, ++ qxl->guest_primary.surface.height, ++ qxl->guest_primary.surface.stride); + + /* dirty the off-screen surfaces */ + for (i = 0; i < qxl->ssd.num_surfaces; i++) { + QXLSurfaceCmd *cmd; +- intptr_t surface_offset; +- int surface_size; + + if (qxl->guest_surfaces.cmds[i] == 0) { + continue; +@@ -1851,15 +1862,9 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + MEMSLOT_GROUP_GUEST); + assert(cmd); + assert(cmd->type == QXL_SURFACE_CMD_CREATE); +- surface_offset = (intptr_t)qxl_phys2virt(qxl, +- cmd->u.surface_create.data, +- MEMSLOT_GROUP_GUEST); +- assert(surface_offset); +- surface_offset -= vram_start; +- surface_size = cmd->u.surface_create.height * +- abs(cmd->u.surface_create.stride); +- trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size); +- qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); ++ qxl_dirty_one_surface(qxl, cmd->u.surface_create.data, ++ cmd->u.surface_create.height, ++ cmd->u.surface_create.stride); + } + } + +diff --git a/trace-events b/trace-events +index b43132c..4da84b2 100644 +--- a/trace-events ++++ b/trace-events +@@ -1078,7 +1078,7 @@ qxl_spice_reset_image_cache(int qid) "%d" + qxl_spice_reset_memslots(int qid) "%d" + qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" + qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" +-qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" ++qxl_surfaces_dirty(int qid, int offset, int size) "%d offset=%d size=%d" + qxl_send_events(int qid, uint32_t events) "%d %d" + qxl_send_events_vm_stopped(int qid, uint32_t events) "%d %d" + qxl_set_guest_bug(int qid) "%d" +-- +1.8.3.1 + diff --git a/SOURCES/kvm-qxl-store-memory-region-and-offset-instead-of-pointe.patch b/SOURCES/kvm-qxl-store-memory-region-and-offset-instead-of-pointe.patch new file mode 100644 index 0000000..4d64bef --- /dev/null +++ b/SOURCES/kvm-qxl-store-memory-region-and-offset-instead-of-pointe.patch @@ -0,0 +1,109 @@ +From 8f25ff7e1496ce8a26edacfa01c64f3a98c564a0 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 22 Jul 2016 09:34:39 +0200 +Subject: [PATCH 2/4] qxl: store memory region and offset instead of pointer + for guest slots + +RH-Author: Gerd Hoffmann +Message-id: <1469180081-28522-3-git-send-email-kraxel@redhat.com> +Patchwork-id: 71314 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 2/4] qxl: store memory region and offset instead of pointer for guest slots +Bugzilla: 1355730 +RH-Acked-by: Laurent Vivier +RH-Acked-by: John Snow +RH-Acked-by: Laszlo Ersek + +Store MemoryRegion and offset instead of a pointer for each qxl memory +slot, so we can easily figure in which memory region an qxl object +stored. + +Signed-off-by: Gerd Hoffmann +Message-id: 1466597244-5938-2-git-send-email-kraxel@redhat.com +(cherry picked from commit 3cb5158f15604a9f50287f2f06777d5835ff4c15) +Signed-off-by: Miroslav Rezanina +--- + hw/display/qxl.c | 15 +++++++++++---- + hw/display/qxl.h | 3 ++- + 2 files changed, 13 insertions(+), 5 deletions(-) + +diff --git a/hw/display/qxl.c b/hw/display/qxl.c +index 5e1ecd8..de5770e 100644 +--- a/hw/display/qxl.c ++++ b/hw/display/qxl.c +@@ -1232,6 +1232,7 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + int pci_region; + pcibus_t pci_start; + pcibus_t pci_end; ++ MemoryRegion *mr; + intptr_t virt_start; + QXLDevMemSlot memslot; + int i; +@@ -1278,11 +1279,11 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + + switch (pci_region) { + case QXL_RAM_RANGE_INDEX: +- virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram); ++ mr = &d->vga.vram; + break; + case QXL_VRAM_RANGE_INDEX: + case 4 /* vram 64bit */: +- virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar); ++ mr = &d->vram_bar; + break; + default: + /* should not happen */ +@@ -1290,6 +1291,7 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + return 1; + } + ++ virt_start = (intptr_t)memory_region_get_ram_ptr(mr); + memslot.slot_id = slot_id; + memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */ + memslot.virt_start = virt_start + (guest_start - pci_start); +@@ -1299,7 +1301,8 @@ static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + qxl_rom_set_dirty(d); + + qemu_spice_add_memslot(&d->ssd, &memslot, async); +- d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; ++ d->guest_slots[slot_id].mr = mr; ++ d->guest_slots[slot_id].offset = memslot.virt_start - virt_start; + d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; + d->guest_slots[slot_id].delta = delta; + d->guest_slots[slot_id].active = 1; +@@ -1366,6 +1369,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + { + uint64_t offset; + uint32_t slot; ++ void *ptr; + + switch (group_id) { + case MEMSLOT_GROUP_HOST: +@@ -1375,7 +1379,10 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + if (!qxl_get_check_slot_offset(qxl, pqxl, &slot, &offset)) { + return NULL; + } +- return qxl->guest_slots[slot].ptr + offset; ++ ptr = memory_region_get_ram_ptr(qxl->guest_slots[slot].mr); ++ ptr += qxl->guest_slots[slot].offset; ++ ptr += offset; ++ return ptr; + } + return NULL; + } +diff --git a/hw/display/qxl.h b/hw/display/qxl.h +index 5247ce9..f3f51e2 100644 +--- a/hw/display/qxl.h ++++ b/hw/display/qxl.h +@@ -49,7 +49,8 @@ typedef struct PCIQXLDevice { + + struct guest_slots { + QXLMemSlot slot; +- void *ptr; ++ MemoryRegion *mr; ++ uint64_t offset; + uint64_t size; + uint64_t delta; + uint32_t active; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-raw-posix-Fetch-max-sectors-for-host-block-device.patch b/SOURCES/kvm-raw-posix-Fetch-max-sectors-for-host-block-device.patch new file mode 100644 index 0000000..e24544e --- /dev/null +++ b/SOURCES/kvm-raw-posix-Fetch-max-sectors-for-host-block-device.patch @@ -0,0 +1,67 @@ +From 52288902dd647cbcfa470a11867163a6e5983297 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 11 Jul 2016 05:33:38 +0200 +Subject: [PATCH 5/7] raw-posix: Fetch max sectors for host block device + +RH-Author: Fam Zheng +Message-id: <1468215219-30793-6-git-send-email-famz@redhat.com> +Patchwork-id: 71109 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 5/6] raw-posix: Fetch max sectors for host block device +Bugzilla: 1318199 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +This is sometimes a useful value we should count in. + +Signed-off-by: Fam Zheng +Reviewed-by: Eric Blake +Signed-off-by: Kevin Wolf +(cherry picked from commit 6f6071745bd0366221f5a0160ed7d18d0e38b9f7) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/raw-posix.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/block/raw-posix.c b/block/raw-posix.c +index 92fcb6c..ed97bd4 100644 +--- a/block/raw-posix.c ++++ b/block/raw-posix.c +@@ -587,9 +587,33 @@ static void raw_reopen_abort(BDRVReopenState *state) + state->opaque = NULL; + } + ++static int hdev_get_max_transfer_length(int fd) ++{ ++#ifdef BLKSECTGET ++ int max_sectors = 0; ++ if (ioctl(fd, BLKSECTGET, &max_sectors) == 0) { ++ return max_sectors; ++ } else { ++ return -errno; ++ } ++#else ++ return -ENOSYS; ++#endif ++} ++ + static void raw_refresh_limits(BlockDriverState *bs, Error **errp) + { + BDRVRawState *s = bs->opaque; ++ struct stat st; ++ ++ if (!fstat(s->fd, &st)) { ++ if (S_ISBLK(st.st_mode)) { ++ int ret = hdev_get_max_transfer_length(s->fd); ++ if (ret >= 0) { ++ bs->bl.max_transfer_length = ret; ++ } ++ } ++ } + + raw_probe_alignment(bs, s->fd, errp); + bs->bl.opt_mem_alignment = s->buf_align; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-raw-posix-Fix-.bdrv_co_get_block_status-for-unaligne.patch b/SOURCES/kvm-raw-posix-Fix-.bdrv_co_get_block_status-for-unaligne.patch index 841b730..adae243 100644 --- a/SOURCES/kvm-raw-posix-Fix-.bdrv_co_get_block_status-for-unaligne.patch +++ b/SOURCES/kvm-raw-posix-Fix-.bdrv_co_get_block_status-for-unaligne.patch @@ -1,13 +1,13 @@ -From 1a4a13c7c0f05f5a423c09607c7ef5151d315242 Mon Sep 17 00:00:00 2001 +From 4237964a9f433faaf643166a8ce9c070dc4cf165 Mon Sep 17 00:00:00 2001 From: Max Reitz -Date: Sat, 16 Jan 2016 14:02:12 +0100 +Date: Thu, 14 Jan 2016 15:10:31 +0100 Subject: [PATCH] raw-posix: Fix .bdrv_co_get_block_status() for unaligned image size -Message-id: <1452952932-2466-2-git-send-email-mreitz@redhat.com> -Patchwork-id: 68783 -O-Subject: [RHEL-7.2.z qemu-kvm PATCH 1/1] raw-posix: Fix .bdrv_co_get_block_status() for unaligned image size -Bugzilla: 1298828 +Message-id: <1452784231-14211-2-git-send-email-mreitz@redhat.com> +Patchwork-id: 68756 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/1] raw-posix: Fix .bdrv_co_get_block_status() for unaligned image size +Bugzilla: 1283116 RH-Acked-by: Fam Zheng RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Kevin Wolf diff --git a/SOURCES/kvm-rbd-fix-ceph-settings-precedence.patch b/SOURCES/kvm-rbd-fix-ceph-settings-precedence.patch index 10d1536..a5b699e 100644 --- a/SOURCES/kvm-rbd-fix-ceph-settings-precedence.patch +++ b/SOURCES/kvm-rbd-fix-ceph-settings-precedence.patch @@ -1,12 +1,12 @@ -From a66fe0ea2e09b8d82a2d8940632ac06ee8bcc579 Mon Sep 17 00:00:00 2001 +From 109d7dedc79629f58fd9b685ccd9990b90f374e9 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 5 Nov 2015 15:20:58 +0100 -Subject: [PATCH 2/2] rbd: fix ceph settings precedence +Subject: [PATCH 3/6] rbd: fix ceph settings precedence Message-id: <1446736858-29005-3-git-send-email-stefanha@redhat.com> Patchwork-id: 68294 O-Subject: [RHEL-7.2.z qemu-kvm PATCH 2/2] rbd: fix ceph settings precedence -Bugzilla: 1279389 +Bugzilla: 1277248 1279389 RH-Acked-by: Max Reitz RH-Acked-by: Jeffrey Cody RH-Acked-by: Kevin Wolf diff --git a/SOURCES/kvm-rbd-make-qemu-s-cache-setting-override-any-ceph-sett.patch b/SOURCES/kvm-rbd-make-qemu-s-cache-setting-override-any-ceph-sett.patch index 8a8bbe7..22705e6 100644 --- a/SOURCES/kvm-rbd-make-qemu-s-cache-setting-override-any-ceph-sett.patch +++ b/SOURCES/kvm-rbd-make-qemu-s-cache-setting-override-any-ceph-sett.patch @@ -1,12 +1,12 @@ -From 6f293e47850a873d0ccc39882be7b3ef6e1043b6 Mon Sep 17 00:00:00 2001 +From 23bc583f18eb8ffc28604a4ae42e2f7a55b31c3e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 5 Nov 2015 15:20:57 +0100 -Subject: [PATCH 1/2] rbd: make qemu's cache setting override any ceph setting +Subject: [PATCH 2/6] rbd: make qemu's cache setting override any ceph setting Message-id: <1446736858-29005-2-git-send-email-stefanha@redhat.com> Patchwork-id: 68293 O-Subject: [RHEL-7.2.z qemu-kvm PATCH 1/2] rbd: make qemu's cache setting override any ceph setting -Bugzilla: 1279389 +Bugzilla: 1277248 RH-Acked-by: Max Reitz RH-Acked-by: Jeffrey Cody RH-Acked-by: Kevin Wolf diff --git a/SOURCES/kvm-rtl8139-Do-not-consume-the-packet-during-overflow-in.patch b/SOURCES/kvm-rtl8139-Do-not-consume-the-packet-during-overflow-in.patch new file mode 100644 index 0000000..db4b86a --- /dev/null +++ b/SOURCES/kvm-rtl8139-Do-not-consume-the-packet-during-overflow-in.patch @@ -0,0 +1,48 @@ +From 9318bd2b84409c6f3810d410c6918fefec072408 Mon Sep 17 00:00:00 2001 +From: Vlad Yasevich +Date: Wed, 16 Dec 2015 02:58:23 +0100 +Subject: [PATCH 6/6] rtl8139: Do not consume the packet during overflow in + standard mode. + +Message-id: <1450234703-7606-3-git-send-email-vyasevic@redhat.com> +Patchwork-id: 68618 +O-Subject: [RHEL7.3 qemu-kvm PATCH 2/2] rtl8139: Do not consume the packet during overflow in standard mode. +Bugzilla: 1252757 +RH-Acked-by: Thomas Huth +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Xiao Wang + +When operation in standard mode, we currently return the size +of packet during buffer overflow. This consumes the overflow +packet. Return 0 instead so we can re-process the overflow packet +when we have room. + +This fixes issues with lost/dropped fragments of large messages. + +Signed-off-by: Vladislav Yasevich +Reviewed-by: Jason Wang +Message-id: 1441121206-6997-3-git-send-email-vyasevic@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 26c4e7ca72d970d120f0f51244bc8d37458512a0) +Signed-off-by: Vladislav Yasevich +Signed-off-by: Miroslav Rezanina +--- + hw/net/rtl8139.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c +index 6a167df..aa2503d 100644 +--- a/hw/net/rtl8139.c ++++ b/hw/net/rtl8139.c +@@ -1148,7 +1148,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t + s->IntrStatus |= RxOverflow; + ++s->RxMissed; + rtl8139_update_irq(s); +- return size_; ++ return 0; + } + + packet_header |= RxStatusOK; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-rtl8139-Fix-receive-buffer-overflow-check.patch b/SOURCES/kvm-rtl8139-Fix-receive-buffer-overflow-check.patch new file mode 100644 index 0000000..7399163 --- /dev/null +++ b/SOURCES/kvm-rtl8139-Fix-receive-buffer-overflow-check.patch @@ -0,0 +1,64 @@ +From dc546cbfdefb8ddbaf121d3b075ca723df264d1c Mon Sep 17 00:00:00 2001 +From: Vlad Yasevich +Date: Wed, 16 Dec 2015 02:58:22 +0100 +Subject: [PATCH 5/6] rtl8139: Fix receive buffer overflow check + +Message-id: <1450234703-7606-2-git-send-email-vyasevic@redhat.com> +Patchwork-id: 68617 +O-Subject: [RHEL7.3 qemu-kvm PATCH 1/2] rtl8139: Fix receive buffer overflow check +Bugzilla: 1252757 +RH-Acked-by: Thomas Huth +RH-Acked-by: Michael S. Tsirkin +RH-Acked-by: Xiao Wang + +rtl8139_do_receive() tries to check for the overflow condition +by making sure that packet_size + 8 does not exceed the +available buffer space. The issue here is that RxBuffAddr, +used to calculate available buffer space, is aligned to a +a 4 byte boundry after every update. So it is possible that +every packet ends up being slightly padded when written +to the receive buffer. This padding is not taken into +account when checking for overflow and we may end up missing +the overflow condition can causing buffer overwrite. + +This patch takes alignment into consideration when +checking for overflow condition. + +Signed-off-by: Vladislav Yasevich +Reviewed-by: Jason Wang +Message-id: 1441121206-6997-2-git-send-email-vyasevic@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit fabdcd3392f16fc666b1d04fc1bbe5f1dbbf10a4) +Signed-off-by: Vladislav Yasevich +Signed-off-by: Miroslav Rezanina +--- + hw/net/rtl8139.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c +index 4f89328..6a167df 100644 +--- a/hw/net/rtl8139.c ++++ b/hw/net/rtl8139.c +@@ -1137,7 +1137,9 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t + + /* if receiver buffer is empty then avail == 0 */ + +- if (avail != 0 && size + 8 >= avail) ++#define RX_ALIGN(x) (((x) + 3) & ~0x3) ++ ++ if (avail != 0 && RX_ALIGN(size + 8) >= avail) + { + DPRINTF("rx overflow: rx buffer length %d head 0x%04x " + "read 0x%04x === available 0x%04x need 0x%04x\n", +@@ -1165,7 +1167,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t + rtl8139_write_buffer(s, (uint8_t *)&val, 4); + + /* correct buffer write pointer */ +- s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize); ++ s->RxBufAddr = MOD2(RX_ALIGN(s->RxBufAddr), s->RxBufferSize); + + /* now we can signal we have received something */ + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-Advertise-limits-by-blocksize-not-512.patch b/SOURCES/kvm-scsi-Advertise-limits-by-blocksize-not-512.patch new file mode 100644 index 0000000..4d7aed1 --- /dev/null +++ b/SOURCES/kvm-scsi-Advertise-limits-by-blocksize-not-512.patch @@ -0,0 +1,54 @@ +From c8644154fb4b460f00c9d24ed9090edc40fef067 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 11 Jul 2016 05:33:39 +0200 +Subject: [PATCH 6/7] scsi: Advertise limits by blocksize, not 512 + +RH-Author: Fam Zheng +Message-id: <1468215219-30793-7-git-send-email-famz@redhat.com> +Patchwork-id: 71110 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 6/6] scsi: Advertise limits by blocksize, not 512 +Bugzilla: 1318199 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Eric Blake + +s->blocksize may be larger than 512, in which case our +tweaks to max_xfer_len and opt_xfer_len must be scaled +appropriately. + +CC: qemu-stable@nongnu.org +Reported-by: Fam Zheng +Signed-off-by: Eric Blake +Reviewed-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit efaf4781a995aacd22b1dd521b14e4644bafae14) + + Conflicts: + hw/scsi/scsi-generic.c +Downstream uses bdrv_get_max_transfer_length(). + +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/scsi-generic.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index 6b0c1fe..ced92f7 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -210,7 +210,8 @@ static void scsi_read_complete(void * opaque, int ret) + } else if (s->type == TYPE_DISK && + r->req.cmd.buf[0] == INQUIRY && + r->req.cmd.buf[2] == 0xb0) { +- uint32_t max_xfer_len = bdrv_get_max_transfer_length(s->conf.bs); ++ uint32_t max_xfer_len = bdrv_get_max_transfer_length(s->conf.bs) / ++ (s->blocksize / BDRV_SECTOR_SIZE); + if (max_xfer_len) { + stl_be_p(&r->buf[8], max_xfer_len); + /* Also take care of the opt xfer len. */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-scsi-generic-Merge-block-max-xfer-len-in-INQUIRY-res.patch b/SOURCES/kvm-scsi-generic-Merge-block-max-xfer-len-in-INQUIRY-res.patch new file mode 100644 index 0000000..9f465df --- /dev/null +++ b/SOURCES/kvm-scsi-generic-Merge-block-max-xfer-len-in-INQUIRY-res.patch @@ -0,0 +1,67 @@ +From b3f427e4eb27091ca712f6c18e2e63a414dc4ce2 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 11 Jul 2016 05:33:37 +0200 +Subject: [PATCH 4/7] scsi-generic: Merge block max xfer len in INQUIRY + response + +RH-Author: Fam Zheng +Message-id: <1468215219-30793-5-git-send-email-famz@redhat.com> +Patchwork-id: 71108 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 4/6] scsi-generic: Merge block max xfer len in INQUIRY response +Bugzilla: 1318199 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +The rationale is similar to the above mode sense response interception: +this is practically the only channel to communicate restraints from +elsewhere such as host and block driver. + +The scsi bus we attach onto can have a larger max xfer len than what is +accepted by the host file system (guarding between the host scsi LUN and +QEMU), in which case the SG_IO we generate would get -EINVAL. + +Signed-off-by: Fam Zheng +Message-Id: <1464243305-10661-3-git-send-email-famz@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 063143d5b1fde0fdcbae30bc7d6d14e76fa607d2) +Signed-off-by: Miroslav Rezanina + +Conflicts: + hw/scsi/scsi-generic.c +We don't have BlockBackend in downstream, use bdrv_get_max_transfer_length() +instead. + +The context is different because we don't have fa0d653b0 (scsi-generic: +identify AIO callbacks more clearly). + +Signed-off-by: Fam Zheng +--- + hw/scsi/scsi-generic.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c +index 3733d2c..6b0c1fe 100644 +--- a/hw/scsi/scsi-generic.c ++++ b/hw/scsi/scsi-generic.c +@@ -207,6 +207,17 @@ static void scsi_read_complete(void * opaque, int ret) + (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { + s->blocksize = ldl_be_p(&r->buf[8]); + s->max_lba = ldq_be_p(&r->buf[0]); ++ } else if (s->type == TYPE_DISK && ++ r->req.cmd.buf[0] == INQUIRY && ++ r->req.cmd.buf[2] == 0xb0) { ++ uint32_t max_xfer_len = bdrv_get_max_transfer_length(s->conf.bs); ++ if (max_xfer_len) { ++ stl_be_p(&r->buf[8], max_xfer_len); ++ /* Also take care of the opt xfer len. */ ++ if (ldl_be_p(&r->buf[12]) > max_xfer_len) { ++ stl_be_p(&r->buf[12], max_xfer_len); ++ } ++ } + } + bdrv_set_guest_block_size(s->conf.bs, s->blocksize); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-seccomp-adding-sysinfo-system-call-to-whitelist.patch b/SOURCES/kvm-seccomp-adding-sysinfo-system-call-to-whitelist.patch new file mode 100644 index 0000000..1e6fac4 --- /dev/null +++ b/SOURCES/kvm-seccomp-adding-sysinfo-system-call-to-whitelist.patch @@ -0,0 +1,48 @@ +From 2dc9b654f678a1cfa95a680f31085cdff1e648b2 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Fri, 22 Apr 2016 05:14:07 +0200 +Subject: [PATCH 02/10] seccomp: adding sysinfo system call to whitelist + +RH-Author: Miroslav Rezanina +Message-id: <1461302047-6677-1-git-send-email-mrezanin@redhat.com> +Patchwork-id: 70221 +O-Subject: [RHEL 7.3 qemu-kvm PATCH] seccomp: adding sysinfo system call to whitelist +Bugzilla: 1177318 +RH-Acked-by: Thomas Huth +RH-Acked-by: Markus Armbruster +RH-Acked-by: Stefan Hajnoczi + +From: Miroslav Rezanina + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1177318 +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=10914613 +RHEV: BZ 1177309, fixed with 2.6 rebase + +Newer version of nss-softokn libraries (> 3.16.2.3) use sysinfo call +so qemu using rbd image hang after start when run in sandbox mode. + +To allow using rbd images in sandbox mode we have to whitelist it. + +Signed-off-by: Miroslav Rezanina +Acked-by: Eduardo Otubo +(cherry picked from commit 8e08f8a4a7f613af65b29fcc3ac3bfc2a08a3343) +Signed-off-by: Miroslav Rezanina +--- + qemu-seccomp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/qemu-seccomp.c b/qemu-seccomp.c +index 5e60fce..e947909 100644 +--- a/qemu-seccomp.c ++++ b/qemu-seccomp.c +@@ -249,6 +249,7 @@ static const struct QemuSeccompSyscall seccomp_whitelist[] = { + { SCMP_SYS(munlock), 240 }, + { SCMP_SYS(semctl), 240 }, + { SCMP_SYS(timerfd_create), 240 }, ++ { SCMP_SYS(sysinfo), 240 }, + }; + + int seccomp_start(void) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-spice-do-not-require-TCP-ports.patch b/SOURCES/kvm-spice-do-not-require-TCP-ports.patch new file mode 100644 index 0000000..7e0f350 --- /dev/null +++ b/SOURCES/kvm-spice-do-not-require-TCP-ports.patch @@ -0,0 +1,48 @@ +From f40c437eed664b31984a21ec6bbed12c6b03dd0b Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 1 Jun 2016 13:16:08 +0200 +Subject: [PATCH 1/2] spice: do not require TCP ports +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Gerd Hoffmann +Message-id: <1464786968-25518-2-git-send-email-kraxel@redhat.com> +Patchwork-id: 70523 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/1] spice: do not require TCP ports +Bugzilla: 1336491 +RH-Acked-by: Laurent Vivier +RH-Acked-by: Thomas Huth +RH-Acked-by: Laszlo Ersek + +From: Marc-André Lureau + +It is possible to use Spice server without TCP port. On local VM, +qemu (and libvirt) can add new clients thanks to QMP add_client command. + +Signed-off-by: Marc-André Lureau +Signed-off-by: Gerd Hoffmann +(cherry picked from commit cf7856adefebe86e0cd50302d93b3045e3111690) +Signed-off-by: Miroslav Rezanina +--- + ui/spice-core.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 141afd1..8d6e726 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -648,10 +648,6 @@ void qemu_spice_init(void) + } + port = qemu_opt_get_number(opts, "port", 0); + tls_port = qemu_opt_get_number(opts, "tls-port", 0); +- if (!port && !tls_port) { +- error_report("neither port nor tls-port specified for spice"); +- exit(1); +- } + if (port < 0 || port > 65535) { + error_report("spice port is out of range"); + exit(1); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-Add-more-Intel-AVX-512-instructions-supp.patch b/SOURCES/kvm-target-i386-Add-more-Intel-AVX-512-instructions-supp.patch new file mode 100644 index 0000000..85efb16 --- /dev/null +++ b/SOURCES/kvm-target-i386-Add-more-Intel-AVX-512-instructions-supp.patch @@ -0,0 +1,93 @@ +From 73b0c0b62c08330e65e9ec3d54ae5738d4b5211d Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Fri, 9 Sep 2016 19:08:34 +0200 +Subject: [PATCH 2/2] target-i386: Add more Intel AVX-512 instructions support + +RH-Author: Eduardo Habkost +Message-id: <1473448114-1430-3-git-send-email-ehabkost@redhat.com> +Patchwork-id: 72277 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 2/2] target-i386: Add more Intel AVX-512 instructions support +Bugzilla: 1372459 +RH-Acked-by: Bandan Das +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Paolo Bonzini + +From: Luwei Kang + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1372459 + +Add more AVX512 feature bits, include AVX512DQ, AVX512IFMA, +AVX512BW, AVX512VL, AVX512VBMI. Its spec can be found at: +https://software.intel.com/sites/default/files/managed/b4/3a/319433-024.pdf + +Signed-off-by: Luwei Kang +Signed-off-by: Eduardo Habkost +(cherry picked from commit cc728d1493eee3e20c1547191862e43d3f55e714) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target-i386/cpu.c | 14 +++++++++----- + target-i386/cpu.h | 13 +++++++++++++ + 2 files changed, 22 insertions(+), 5 deletions(-) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index d9c214c..476306d 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -144,14 +144,18 @@ static const char *svm_feature_name[] = { + }; + + static const char *cpuid_7_0_ebx_feature_name[] = { +- "fsgsbase", NULL, NULL, "bmi1", "hle", "avx2", NULL, "smep", +- "bmi2", "erms", "invpcid", "rtm", NULL, NULL, "mpx", NULL, +- "avx512f", NULL, "rdseed", "adx", "smap", NULL, NULL, NULL, +- NULL, NULL, "avx512pf", "avx512er", "avx512cd", NULL, NULL, NULL, ++ "fsgsbase", NULL, NULL, "bmi1", ++ "hle", "avx2", NULL, "smep", ++ "bmi2", "erms", "invpcid", "rtm", ++ NULL, NULL, "mpx", NULL, ++ "avx512f", "avx512dq", "rdseed", "adx", ++ "smap", "avx512ifma", NULL, NULL, ++ NULL, NULL, "avx512pf", "avx512er", ++ "avx512cd", NULL, "avx512bw", "avx512vl", + }; + + static const char *cpuid_7_0_ecx_feature_name[] = { +- NULL, NULL, NULL, NULL, ++ NULL, "avx512vbmi", NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, +diff --git a/target-i386/cpu.h b/target-i386/cpu.h +index 5c62ee3..d541809 100644 +--- a/target-i386/cpu.h ++++ b/target-i386/cpu.h +@@ -560,12 +560,25 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; + #define CPUID_7_0_EBX_RTM (1U << 11) + #define CPUID_7_0_EBX_MPX (1U << 14) + #define CPUID_7_0_EBX_AVX512F (1U << 16) /* AVX-512 Foundation */ ++#define CPUID_7_0_EBX_AVX512DQ (1U << 17) /* AVX-512 Doubleword & Quadword Instrs */ + #define CPUID_7_0_EBX_RDSEED (1U << 18) + #define CPUID_7_0_EBX_ADX (1U << 19) + #define CPUID_7_0_EBX_SMAP (1U << 20) ++#define CPUID_7_0_EBX_AVX512IFMA (1U << 21) /* AVX-512 Integer Fused Multiply Add */ ++#define CPUID_7_0_EBX_PCOMMIT (1U << 22) /* Persistent Commit */ ++#define CPUID_7_0_EBX_CLFLUSHOPT (1U << 23) /* Flush a Cache Line Optimized */ ++#define CPUID_7_0_EBX_CLWB (1U << 24) /* Cache Line Write Back */ + #define CPUID_7_0_EBX_AVX512PF (1U << 26) /* AVX-512 Prefetch */ + #define CPUID_7_0_EBX_AVX512ER (1U << 27) /* AVX-512 Exponential and Reciprocal */ + #define CPUID_7_0_EBX_AVX512CD (1U << 28) /* AVX-512 Conflict Detection */ ++#define CPUID_7_0_EBX_AVX512BW (1U << 30) /* AVX-512 Byte and Word Instructions */ ++#define CPUID_7_0_EBX_AVX512VL (1U << 31) /* AVX-512 Vector Length Extensions */ ++ ++#define CPUID_7_0_ECX_VBMI (1U << 1) /* AVX-512 Vector Byte Manipulation Instrs */ ++#define CPUID_7_0_ECX_UMIP (1U << 2) ++#define CPUID_7_0_ECX_PKU (1U << 3) ++#define CPUID_7_0_ECX_OSPKE (1U << 4) ++#define CPUID_7_0_ECX_RDPID (1U << 22) + + #define CPUID_XSAVE_XSAVEOPT (1U << 0) + #define CPUID_XSAVE_XSAVEC (1U << 1) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-Add-support-for-FEAT_7_0_ECX.patch b/SOURCES/kvm-target-i386-Add-support-for-FEAT_7_0_ECX.patch new file mode 100644 index 0000000..43d29aa --- /dev/null +++ b/SOURCES/kvm-target-i386-Add-support-for-FEAT_7_0_ECX.patch @@ -0,0 +1,147 @@ +From eb87f1106d038247356ecd3071e6fa5654386ff5 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Fri, 9 Sep 2016 19:08:33 +0200 +Subject: [PATCH 1/2] target-i386: Add support for FEAT_7_0_ECX + +RH-Author: Eduardo Habkost +Message-id: <1473448114-1430-2-git-send-email-ehabkost@redhat.com> +Patchwork-id: 72276 +O-Subject: [RHEL-7.3 qemu-kvm PATCH v2 1/2] target-i386: Add support for FEAT_7_0_ECX +Bugzilla: 1372459 +RH-Acked-by: Bandan Das +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Paolo Bonzini + +From: Paolo Bonzini + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1372459 + +Done from scratch by copying what is done for FEAT_7_0_EBX. Compare +to upstream commit f74eefe ("target-i386: Add PKU and and OSPKE support", +2016-01-21), but without actually adding PKU and OSPKE. Because all +these features are "-cpu host"-only, they can be added without modifying +machine types. + +Signed-off-by: Paolo Bonzini +[ehabkost: v2: removed the non-upstream cpuid_level < 7 check] +Signed-off-by: Eduardo Habkost + +Signed-off-by: Miroslav Rezanina +--- + target-i386/cpu.c | 29 ++++++++++++++++++++++++++++- + target-i386/cpu.h | 1 + + 2 files changed, 29 insertions(+), 1 deletion(-) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index 1001c47..d9c214c 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -150,6 +150,17 @@ static const char *cpuid_7_0_ebx_feature_name[] = { + NULL, NULL, "avx512pf", "avx512er", "avx512cd", NULL, NULL, NULL, + }; + ++static const char *cpuid_7_0_ecx_feature_name[] = { ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++}; ++ + static const char *cpuid_xsave_feature_name[] = { + "xsaveopt", "xsavec", "xgetbv1", NULL, + NULL, NULL, NULL, NULL, +@@ -204,6 +215,12 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .cpuid_needs_ecx = true, .cpuid_ecx = 0, + .cpuid_reg = R_EBX, + }, ++ [FEAT_7_0_ECX] = { ++ .feat_names = cpuid_7_0_ecx_feature_name, ++ .cpuid_eax = 7, ++ .cpuid_needs_ecx = true, .cpuid_ecx = 0, ++ .cpuid_reg = R_ECX, ++ }, + [FEAT_XSAVE] = { + .feat_names = cpuid_xsave_feature_name, + .cpuid_eax = 0xd, +@@ -462,6 +479,7 @@ typedef struct x86_def_t { + CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, + CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, + CPUID_7_0_EBX_RDSEED */ ++#define TCG_7_0_ECX_FEATURES 0 + + /* built-in CPU model definitions + */ +@@ -1198,8 +1216,11 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) + if (x86_cpu_def->level >= 7) { + x86_cpu_def->features[FEAT_7_0_EBX] = + kvm_arch_get_supported_cpuid(s, 0x7, 0, R_EBX); ++ x86_cpu_def->features[FEAT_7_0_ECX] = ++ kvm_arch_get_supported_cpuid(s, 0x7, 0, R_ECX); + } else { + x86_cpu_def->features[FEAT_7_0_EBX] = 0; ++ x86_cpu_def->features[FEAT_7_0_ECX] = 0; + } + x86_cpu_def->features[FEAT_XSAVE] = + kvm_arch_get_supported_cpuid(s, 0xd, 1, R_EAX); +@@ -1283,6 +1304,9 @@ static int kvm_check_features_against_host(X86CPU *cpu) + {&env->features[FEAT_7_0_EBX], + &host_def.features[FEAT_7_0_EBX], + FEAT_7_0_EBX }, ++ {&env->features[FEAT_7_0_ECX], ++ &host_def.features[FEAT_7_0_ECX], ++ FEAT_7_0_ECX }, + {&env->features[FEAT_XSAVE], + &host_def.features[FEAT_XSAVE], + FEAT_XSAVE }, +@@ -1824,6 +1848,7 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) + env->features[FEAT_KVM] |= plus_features[FEAT_KVM]; + env->features[FEAT_SVM] |= plus_features[FEAT_SVM]; + env->features[FEAT_7_0_EBX] |= plus_features[FEAT_7_0_EBX]; ++ env->features[FEAT_7_0_ECX] |= plus_features[FEAT_7_0_ECX]; + env->features[FEAT_XSAVE] |= plus_features[FEAT_XSAVE]; + env->features[FEAT_1_EDX] &= ~minus_features[FEAT_1_EDX]; + env->features[FEAT_1_ECX] &= ~minus_features[FEAT_1_ECX]; +@@ -1833,6 +1858,7 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) + env->features[FEAT_KVM] &= ~minus_features[FEAT_KVM]; + env->features[FEAT_SVM] &= ~minus_features[FEAT_SVM]; + env->features[FEAT_7_0_EBX] &= ~minus_features[FEAT_7_0_EBX]; ++ env->features[FEAT_7_0_ECX] &= ~minus_features[FEAT_7_0_ECX]; + env->features[FEAT_XSAVE] &= ~minus_features[FEAT_XSAVE]; + + out: +@@ -1969,6 +1995,7 @@ static void cpu_x86_register(X86CPU *cpu, const char *name, Error **errp) + env->features[FEAT_SVM] = def->features[FEAT_SVM]; + env->features[FEAT_C000_0001_EDX] = def->features[FEAT_C000_0001_EDX]; + env->features[FEAT_7_0_EBX] = def->features[FEAT_7_0_EBX]; ++ env->features[FEAT_7_0_ECX] = def->features[FEAT_7_0_ECX]; + env->features[FEAT_XSAVE] = def->features[FEAT_XSAVE]; + env->cpuid_xlevel2 = def->xlevel2; + +@@ -2206,7 +2233,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + if (count == 0) { + *eax = 0; /* Maximum ECX value for sub-leaves */ + *ebx = env->features[FEAT_7_0_EBX]; /* Feature flags */ +- *ecx = 0; /* Reserved */ ++ *ecx = env->features[FEAT_7_0_ECX]; /* Feature flags */ + *edx = 0; /* Reserved */ + } else { + *eax = 0; +diff --git a/target-i386/cpu.h b/target-i386/cpu.h +index da7e060..5c62ee3 100644 +--- a/target-i386/cpu.h ++++ b/target-i386/cpu.h +@@ -400,6 +400,7 @@ typedef enum FeatureWord { + FEAT_1_EDX, /* CPUID[1].EDX */ + FEAT_1_ECX, /* CPUID[1].ECX */ + FEAT_7_0_EBX, /* CPUID[EAX=7,ECX=0].EBX */ ++ FEAT_7_0_ECX, /* CPUID[EAX=7,ECX=0].ECX */ + FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */ + FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */ + FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-add-Skylake-Client-cpu-model.patch b/SOURCES/kvm-target-i386-add-Skylake-Client-cpu-model.patch new file mode 100644 index 0000000..e135496 --- /dev/null +++ b/SOURCES/kvm-target-i386-add-Skylake-Client-cpu-model.patch @@ -0,0 +1,92 @@ +From ce561d78c7199821beae26112f41da5733fab5bb Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Wed, 6 Jul 2016 20:47:53 +0200 +Subject: [PATCH 2/2] target-i386: add Skylake-Client cpu model + +RH-Author: Eduardo Habkost +Message-id: <1467838073-23873-3-git-send-email-ehabkost@redhat.com> +Patchwork-id: 71052 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 2/2] target-i386: add Skylake-Client cpu model +Bugzilla: 1327599 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Igor Mammedov +RH-Acked-by: Bandan Das + +Introduce Skylake-Client cpu mode which inherits the features from +Broadwell and supports some additional features that are: MPX, +XSAVEC, and XGETBV1. + +Backport notes: +* ARAT feature not included, as it is not available in the + qemu-kvm-1.5.3 tree (and disabled by compat code in + pc-i440fx-rhel7.2.0 and older on qemu-kvm-rhev) + +Signed-off-by: Eduardo Habkost +Signed-off-by: Xiao Guangrong +Reviewed-by: Paolo Bonzini +Reviewed-by: Xiao Guangrong +Signed-off-by: Eduardo Habkost +(cherry picked from commit f6f949e9295889fb272698aea763dcea77d616ce) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target-i386/cpu.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index 6650c72..80106ba 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -927,6 +927,49 @@ static x86_def_t builtin_x86_defs[] = { + .model_id = "Intel Core Processor (Broadwell)", + }, + { ++ .name = "Skylake-Client", ++ .level = 0xd, ++ .vendor = CPUID_VENDOR_INTEL, ++ .family = 6, ++ .model = 94, ++ .stepping = 3, ++ .features[FEAT_1_EDX] = ++ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | ++ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | ++ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | ++ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | ++ CPUID_DE | CPUID_FP87, ++ .features[FEAT_1_ECX] = ++ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES | ++ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | ++ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | ++ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 | ++ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE | ++ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND, ++ .features[FEAT_8000_0001_EDX] = ++ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX | ++ CPUID_EXT2_SYSCALL, ++ .features[FEAT_8000_0001_ECX] = ++ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH, ++ .features[FEAT_7_0_EBX] = ++ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | ++ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | ++ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | ++ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | ++ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX, ++ /* Missing: XSAVES (not supported by some Linux versions, ++ * including v4.1 to v4.6). ++ * KVM doesn't yet expose any XSAVES state save component, ++ * and the only one defined in Skylake (processor tracing) ++ * probably will block migration anyway. ++ */ ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | ++ CPUID_XSAVE_XGETBV1, ++ .xlevel = 0x80000008, ++ .model_id = "Intel Core Processor (Skylake)", ++ }, ++ { + .name = "Opteron_G1", + .level = 5, + .vendor = CPUID_VENDOR_AMD, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-add-feature-flags-for-CPUID-EAX-0xd-ECX-.patch b/SOURCES/kvm-target-i386-add-feature-flags-for-CPUID-EAX-0xd-ECX-.patch new file mode 100644 index 0000000..14bc767 --- /dev/null +++ b/SOURCES/kvm-target-i386-add-feature-flags-for-CPUID-EAX-0xd-ECX-.patch @@ -0,0 +1,168 @@ +From 5fcaf5176d7545518c76f3aa8ea7ce6fb063c62d Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Wed, 6 Jul 2016 20:47:52 +0200 +Subject: [PATCH 1/2] target-i386: add feature flags for CPUID[EAX=0xd, ECX=1] + +RH-Author: Eduardo Habkost +Message-id: <1467838073-23873-2-git-send-email-ehabkost@redhat.com> +Patchwork-id: 71051 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/2] target-i386: add feature flags for CPUID[EAX=0xd, ECX=1] +Bugzilla: 1327599 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Igor Mammedov +RH-Acked-by: Bandan Das + +From: Paolo Bonzini + +These represent xsave-related capabilities of the processor, and KVM may +or may not support them. + +Add feature bits so that they are considered by "-cpu ...,enforce", and use +the new feature work instead of calling kvm_arch_get_supported_cpuid. + +Bit 3 (XSAVES) is not migratables because it requires saving MSR_IA32_XSS. +Neither KVM nor any commonly available hardware supports it anyway. + +RHEL backport notes: +* In addition to allowing xsave flags to be configured, this + patch is a bug fix because we shouldn't use + kvm_arch_supported_cpuid() directly when configuring CPUID for + the guest +* tcg_features didn't exist, handle it inside x86_cpu_realizefn() + directly in the !kvm_enabled() check +* As the unmigratable_flags mechanism is not present yet, + remove the "xsaves" flag name so it can't be enabled manually + (otherwise we would need to backport upstream commit + 18cd2c17b5370369a886155c001da0a7f54bbcca too) + +Signed-off-by: Paolo Bonzini +(cherry picked from commit 0bb0b2d2fe7f645ddaf1f0ff40ac669c9feb4aa1) +Signed-off-by: Eduardo Habkost +Signed-off-by: Miroslav Rezanina +--- + target-i386/cpu.c | 28 +++++++++++++++++++++++++++- + target-i386/cpu.h | 6 ++++++ + 2 files changed, 33 insertions(+), 1 deletion(-) + +diff --git a/target-i386/cpu.c b/target-i386/cpu.c +index 06efe17..6650c72 100644 +--- a/target-i386/cpu.c ++++ b/target-i386/cpu.c +@@ -150,6 +150,17 @@ static const char *cpuid_7_0_ebx_feature_name[] = { + NULL, NULL, "avx512pf", "avx512er", "avx512cd", NULL, NULL, NULL, + }; + ++static const char *cpuid_xsave_feature_name[] = { ++ "xsaveopt", "xsavec", "xgetbv1", NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, NULL, ++}; ++ + typedef struct FeatureWordInfo { + const char **feat_names; + uint32_t cpuid_eax; /* Input EAX for CPUID */ +@@ -193,6 +204,12 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { + .cpuid_needs_ecx = true, .cpuid_ecx = 0, + .cpuid_reg = R_EBX, + }, ++ [FEAT_XSAVE] = { ++ .feat_names = cpuid_xsave_feature_name, ++ .cpuid_eax = 0xd, ++ .cpuid_needs_ecx = true, .cpuid_ecx = 1, ++ .cpuid_reg = R_EAX, ++ }, + }; + + typedef struct X86RegisterInfo32 { +@@ -833,6 +850,8 @@ static x86_def_t builtin_x86_defs[] = { + CPUID_EXT2_SYSCALL, + .features[FEAT_8000_0001_ECX] = + CPUID_EXT3_LAHF_LM, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT, + .xlevel = 0x8000000A, + .model_id = "Intel Xeon E312xx (Sandy Bridge)", + }, +@@ -866,6 +885,8 @@ static x86_def_t builtin_x86_defs[] = { + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP | + CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | + CPUID_7_0_EBX_RTM, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT, + .xlevel = 0x8000000A, + .model_id = "Intel Core Processor (Haswell)", + }, +@@ -900,6 +921,8 @@ static x86_def_t builtin_x86_defs[] = { + CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID | + CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | + CPUID_7_0_EBX_SMAP, ++ .features[FEAT_XSAVE] = ++ CPUID_XSAVE_XSAVEOPT, + .xlevel = 0x8000000A, + .model_id = "Intel Core Processor (Broadwell)", + }, +@@ -1017,6 +1040,7 @@ static x86_def_t builtin_x86_defs[] = { + CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE | + CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM | + CPUID_EXT3_LAHF_LM, ++ /* no xsaveopt! */ + .xlevel = 0x8000001A, + .model_id = "AMD Opteron 62xx class CPU", + }, +@@ -1051,6 +1075,7 @@ static x86_def_t builtin_x86_defs[] = { + CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_MISALIGNSSE | + CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | CPUID_EXT3_SVM | + CPUID_EXT3_LAHF_LM, ++ /* no xsaveopt! */ + .xlevel = 0x8000001A, + .model_id = "AMD Opteron 63xx class CPU", + }, +@@ -2196,7 +2221,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + *eax |= kvm_mask & (XSTATE_FP | XSTATE_SSE); + *ebx = *ecx; + } else if (count == 1) { +- *eax = kvm_arch_get_supported_cpuid(s, 0xd, 1, R_EAX); ++ *eax = env->features[FEAT_XSAVE]; + } else if (count < ARRAY_SIZE(ext_save_areas)) { + const ExtSaveArea *esa = &ext_save_areas[count]; + if ((env->features[esa->feature] & esa->bits) == esa->bits && +@@ -2540,6 +2565,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) + ); + env->features[FEAT_8000_0001_ECX] &= TCG_EXT3_FEATURES; + env->features[FEAT_SVM] &= TCG_SVM_FEATURES; ++ env->features[FEAT_XSAVE] = 0; + } else { + if ((cpu->check_cpuid || cpu->enforce_cpuid) + && kvm_check_features_against_host(cpu) && cpu->enforce_cpuid) { +diff --git a/target-i386/cpu.h b/target-i386/cpu.h +index 61e9b86..da7e060 100644 +--- a/target-i386/cpu.h ++++ b/target-i386/cpu.h +@@ -405,6 +405,7 @@ typedef enum FeatureWord { + FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ + FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ + FEAT_SVM, /* CPUID[8000_000A].EDX */ ++ FEAT_XSAVE, /* CPUID[EAX=0xd,ECX=1].EAX */ + FEATURE_WORDS, + } FeatureWord; + +@@ -565,6 +566,11 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; + #define CPUID_7_0_EBX_AVX512ER (1U << 27) /* AVX-512 Exponential and Reciprocal */ + #define CPUID_7_0_EBX_AVX512CD (1U << 28) /* AVX-512 Conflict Detection */ + ++#define CPUID_XSAVE_XSAVEOPT (1U << 0) ++#define CPUID_XSAVE_XSAVEC (1U << 1) ++#define CPUID_XSAVE_XGETBV1 (1U << 2) ++#define CPUID_XSAVE_XSAVES (1U << 3) ++ + #define CPUID_VENDOR_SZ 12 + + #define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */ +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-fix-pcmpxstrx-equal-ordered-strstr-mode.patch b/SOURCES/kvm-target-i386-fix-pcmpxstrx-equal-ordered-strstr-mode.patch new file mode 100644 index 0000000..f38645f --- /dev/null +++ b/SOURCES/kvm-target-i386-fix-pcmpxstrx-equal-ordered-strstr-mode.patch @@ -0,0 +1,57 @@ +From b05eb2cc7decc07ed044484861587b3490144d02 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 8 Jun 2016 13:04:21 +0200 +Subject: [PATCH 2/3] target-i386: fix pcmpxstrx equal-ordered (strstr) mode + +RH-Author: Paolo Bonzini +Message-id: <1465391061-17748-1-git-send-email-pbonzini@redhat.com> +Patchwork-id: 70570 +O-Subject: [RHEL7.3/7.2.z qemu-kvm PATCH] target-i386: fix pcmpxstrx equal-ordered (strstr) mode +Bugzilla: 1340971 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Thomas Huth +RH-Acked-by: Laurent Vivier + +Kindly requested by the Openstack folks, who sometimes uses TCG +instead of nested virt. + +In this mode, referring an invalid element of the source forces the +result to false (table 4-7, last column) but referring an invalid +element of the destination forces the result to true, so the outer +loop should still be run even if some elements of the destination +will be invalid. They will be avoided in the inner loop, which +correctly bounds "i" to validd, but they will still contribute to a +positive outcome of the search. + +This fixes tst_strstr in glibc 2.17. + +Reported-by: Florian Weimer +Cc: Richard Henderson +Cc: Eduardo Habkost +Signed-off-by: Paolo Bonzini +(cherry picked from commit 54c54f8b56047d3c2420e1ae06a6a8890c220ac4) +Signed-off-by: Miroslav Rezanina +--- + target-i386/ops_sse.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h +index eb24b5f..5145d9e 100644 +--- a/target-i386/ops_sse.h ++++ b/target-i386/ops_sse.h +@@ -2034,10 +2034,10 @@ static inline unsigned pcmpxstrx(CPUX86State *env, Reg *d, Reg *s, + } + break; + case 3: +- for (j = valids - validd; j >= 0; j--) { ++ for (j = valids; j >= 0; j--) { + res <<= 1; + v = 1; +- for (i = MIN(upper - j, validd); i >= 0; i--) { ++ for (i = MIN(valids - j, validd); i >= 0; i--) { + v &= (pcmp_val(s, ctrl, i + j) == pcmp_val(d, ctrl, i)); + } + res |= v; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-target-i386-get-put-MSR_TSC_AUX-across-reset-and-mig.patch b/SOURCES/kvm-target-i386-get-put-MSR_TSC_AUX-across-reset-and-mig.patch new file mode 100644 index 0000000..17dd46a --- /dev/null +++ b/SOURCES/kvm-target-i386-get-put-MSR_TSC_AUX-across-reset-and-mig.patch @@ -0,0 +1,93 @@ +From f9a24822687113e34194f05aeb641365b8202e9e Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Wed, 25 Nov 2015 05:51:34 +0100 +Subject: [PATCH 4/6] target-i386: get/put MSR_TSC_AUX across reset and + migration + +Message-id: +Patchwork-id: 68467 +O-Subject: [RHEL 7.3 qemu-kvm PATCH 1/1] target-i386: get/put MSR_TSC_AUX across reset and migration +Bugzilla: 1265427 +RH-Acked-by: Juan Quintela +RH-Acked-by: Eduardo Habkost +RH-Acked-by: Paolo Bonzini + +There's one report of migration breaking due to missing MSR_TSC_AUX +save/restore. Fix this by adding a new subsection that saves the state +of this MSR. + +https://bugzilla.redhat.com/show_bug.cgi?id=1261797 + +Reported-by: Xiaoqing Wei +Signed-off-by: Amit Shah +CC: Paolo Bonzini +CC: Juan Quintela +CC: "Dr. David Alan Gilbert" +CC: Marcelo Tosatti +CC: Richard Henderson +CC: Eduardo Habkost +Reviewed-by: Eduardo Habkost +Signed-off-by: Eduardo Habkost +(cherry picked from commit c9b8f6b6210847b4381c5b2ee172b1c7eb9985d6) +Signed-off-by: Amit Shah +Signed-off-by: Miroslav Rezanina +--- + target-i386/kvm.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/target-i386/kvm.c b/target-i386/kvm.c +index c91bfb8..e1b0ca2 100644 +--- a/target-i386/kvm.c ++++ b/target-i386/kvm.c +@@ -63,6 +63,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + + static bool has_msr_star; + static bool has_msr_hsave_pa; ++static bool has_msr_tsc_aux; + static bool has_msr_tsc_adjust; + static bool has_msr_tsc_deadline; + static bool has_msr_async_pf_en; +@@ -774,6 +775,10 @@ static int kvm_get_supported_msrs(KVMState *s) + has_msr_hsave_pa = true; + continue; + } ++ if (kvm_msr_list->indices[i] == MSR_TSC_AUX) { ++ has_msr_tsc_aux = true; ++ continue; ++ } + if (kvm_msr_list->indices[i] == MSR_TSC_ADJUST) { + has_msr_tsc_adjust = true; + continue; +@@ -1159,6 +1164,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level) + if (has_msr_hsave_pa) { + kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave); + } ++ if (has_msr_tsc_aux) { ++ kvm_msr_entry_set(&msrs[n++], MSR_TSC_AUX, env->tsc_aux); ++ } + if (has_msr_tsc_adjust) { + kvm_msr_entry_set(&msrs[n++], MSR_TSC_ADJUST, env->tsc_adjust); + } +@@ -1507,6 +1515,9 @@ static int kvm_get_msrs(X86CPU *cpu) + if (has_msr_hsave_pa) { + msrs[n++].index = MSR_VM_HSAVE_PA; + } ++ if (has_msr_tsc_aux) { ++ msrs[n++].index = MSR_TSC_AUX; ++ } + if (has_msr_tsc_adjust) { + msrs[n++].index = MSR_TSC_ADJUST; + } +@@ -1636,6 +1647,9 @@ static int kvm_get_msrs(X86CPU *cpu) + case MSR_IA32_TSC: + env->tsc = msrs[i].data; + break; ++ case MSR_TSC_AUX: ++ env->tsc_aux = msrs[i].data; ++ break; + case MSR_TSC_ADJUST: + env->tsc_adjust = msrs[i].data; + break; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-trace-remove-malloc-tracing.patch b/SOURCES/kvm-trace-remove-malloc-tracing.patch new file mode 100644 index 0000000..ef72ff0 --- /dev/null +++ b/SOURCES/kvm-trace-remove-malloc-tracing.patch @@ -0,0 +1,104 @@ +From d15566b6a91973dbf83c92a9678bd3ac4939af75 Mon Sep 17 00:00:00 2001 +From: Miroslav Rezanina +Date: Fri, 29 Jul 2016 07:41:27 +0200 +Subject: [PATCH 16/16] trace: remove malloc tracing + +RH-Author: Miroslav Rezanina +Message-id: <1469778087-316-1-git-send-email-mrezanin@redhat.com> +Patchwork-id: 71514 +O-Subject: [RHEL-7.3 qemu-kvm PATCH] trace: remove malloc tracing +Bugzilla: 1360137 +RH-Acked-by: Fam Zheng +RH-Acked-by: Markus Armbruster +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Laurent Vivier + +From: Paolo Bonzini + +The malloc vtable is not supported anymore in glib, because it broke +when constructors called g_malloc. Remove tracing of g_malloc, +g_realloc and g_free calls. + +Note that, for systemtap users, glib also provides tracepoints +glib.mem_alloc, glib.mem_free, glib.mem_realloc, glib.slice_alloc +and glib.slice_free. + +Signed-off-by: Paolo Bonzini +Reviewed-by: Alberto Garcia +Message-id: 1442417924-25831-1-git-send-email-pbonzini@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 98cf48f60aa4999f5b2808569a193a401a390e6a) +Signed-off-by: Miroslav Rezanina +--- + trace-events | 3 --- + vl.c | 26 -------------------------- + 2 files changed, 29 deletions(-) + +diff --git a/trace-events b/trace-events +index af5147a..6cd46e9 100644 +--- a/trace-events ++++ b/trace-events +@@ -474,9 +474,6 @@ scsi_request_sense(int target, int lun, int tag) "target %d lun %d tag %d" + vm_state_notify(int running, int reason) "running %d reason %d" + load_file(const char *name, const char *path) "name %s location %s" + runstate_set(int new_state) "new state %d" +-g_malloc(size_t size, void *ptr) "size %zu ptr %p" +-g_realloc(void *ptr, size_t size, void *newptr) "ptr %p size %zu newptr %p" +-g_free(void *ptr) "ptr %p" + qemu_system_shutdown_request(void) "" + qemu_system_powerdown_request(void) "" + +diff --git a/vl.c b/vl.c +index 35b927e..9756361 100644 +--- a/vl.c ++++ b/vl.c +@@ -2738,26 +2738,6 @@ static const QEMUOption *lookup_opt(int argc, char **argv, + return popt; + } + +-static gpointer malloc_and_trace(gsize n_bytes) +-{ +- void *ptr = malloc(n_bytes); +- trace_g_malloc(n_bytes, ptr); +- return ptr; +-} +- +-static gpointer realloc_and_trace(gpointer mem, gsize n_bytes) +-{ +- void *ptr = realloc(mem, n_bytes); +- trace_g_realloc(mem, n_bytes, ptr); +- return ptr; +-} +- +-static void free_and_trace(gpointer mem) +-{ +- trace_g_free(mem); +- free(mem); +-} +- + static int object_set_property(const char *name, const char *value, void *opaque) + { + Object *obj = OBJECT(opaque); +@@ -2832,11 +2812,6 @@ int main(int argc, char **argv, char **envp) + bool userconfig = true; + const char *log_mask = NULL; + const char *log_file = NULL; +- GMemVTable mem_trace = { +- .malloc = malloc_and_trace, +- .realloc = realloc_and_trace, +- .free = free_and_trace, +- }; + const char *trace_events = NULL; + const char *trace_file = NULL; + FILE *vmstate_dump_file = NULL; +@@ -2845,7 +2820,6 @@ int main(int argc, char **argv, char **envp) + error_set_progname(argv[0]); + qemu_init_exec_dir(argv[0]); + +- g_mem_set_vtable(&mem_trace); + if (!g_thread_supported()) { + #if !GLIB_CHECK_VERSION(2, 31, 0) + g_thread_init(NULL); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-util-Fix-MIN_NON_ZERO.patch b/SOURCES/kvm-util-Fix-MIN_NON_ZERO.patch new file mode 100644 index 0000000..6b2577a --- /dev/null +++ b/SOURCES/kvm-util-Fix-MIN_NON_ZERO.patch @@ -0,0 +1,46 @@ +From 756b23c15387acefe4139831c2f3c8a5f3d41bb2 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 18 Jul 2016 01:32:10 +0200 +Subject: [PATCH 7/7] util: Fix MIN_NON_ZERO + +RH-Author: Fam Zheng +Message-id: <1468805530-19033-1-git-send-email-famz@redhat.com> +Patchwork-id: 71200 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 7/6] util: Fix MIN_NON_ZERO +Bugzilla: 1318199 +RH-Acked-by: John Snow +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Miroslav Rezanina + +MIN_NON_ZERO(1, 0) is evaluated to 0. Rewrite the macro to fix it. + +Reported-by: Miroslav Rezanina +Signed-off-by: Fam Zheng +Message-Id: <1468306113-847-1-git-send-email-famz@redhat.com> +Reviewed-by: Eric Blake +Signed-off-by: Paolo Bonzini +(cherry picked from commit d27ba624aa1dfe5c07cc01200d95967ffce905d9) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + include/qemu/osdep.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h +index c47a600..5ca05bc 100644 +--- a/include/qemu/osdep.h ++++ b/include/qemu/osdep.h +@@ -71,7 +71,8 @@ typedef signed int int_fast16_t; + /* Minimum function that returns zero only iff both values are zero. + * Intended for use with unsigned values only. */ + #ifndef MIN_NON_ZERO +-#define MIN_NON_ZERO(a, b) (((a) != 0 && (a) < (b)) ? (a) : (b)) ++#define MIN_NON_ZERO(a, b) ((a) == 0 ? (b) : \ ++ ((b) == 0 ? (a) : (MIN(a, b)))) + #endif + + #ifndef ROUND_UP +-- +1.8.3.1 + diff --git a/SOURCES/kvm-util-introduce-MIN_NON_ZERO.patch b/SOURCES/kvm-util-introduce-MIN_NON_ZERO.patch new file mode 100644 index 0000000..38e74e5 --- /dev/null +++ b/SOURCES/kvm-util-introduce-MIN_NON_ZERO.patch @@ -0,0 +1,52 @@ +From 6e14ac55a7b40804cf69de560f38561214129b07 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 11 Jul 2016 05:33:34 +0200 +Subject: [PATCH 1/7] util: introduce MIN_NON_ZERO + +RH-Author: Fam Zheng +Message-id: <1468215219-30793-2-git-send-email-famz@redhat.com> +Patchwork-id: 71105 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/6] util: introduce MIN_NON_ZERO +Bugzilla: 1318199 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: John Snow +RH-Acked-by: Paolo Bonzini + +From: Peter Lieven + +at least in block layer we have the case of limits being defined for a +BlockDriverState. However, in this context often zero (0) has the special +meanining of undefined which means no limit. If two of those limits are +combined and the minimum is needed the minimum function should only return +zero if both parameters are zero. + +Signed-off-by: Peter Lieven +Reviewed-by: Max Reitz +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit ac3a8726644d4783eacf54212d23db01d1d30044) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + include/qemu/osdep.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h +index 8984da0..c47a600 100644 +--- a/include/qemu/osdep.h ++++ b/include/qemu/osdep.h +@@ -68,6 +68,12 @@ typedef signed int int_fast16_t; + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) + #endif + ++/* Minimum function that returns zero only iff both values are zero. ++ * Intended for use with unsigned values only. */ ++#ifndef MIN_NON_ZERO ++#define MIN_NON_ZERO(a, b) (((a) != 0 && (a) < (b)) ? (a) : (b)) ++#endif ++ + #ifndef ROUND_UP + #define ROUND_UP(n,d) (((n) + (d) - 1) & -(d)) + #endif +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vga-Remove-some-should-be-done-in-BIOS-comments.patch b/SOURCES/kvm-vga-Remove-some-should-be-done-in-BIOS-comments.patch index 993d0ae..5cfc3f5 100644 --- a/SOURCES/kvm-vga-Remove-some-should-be-done-in-BIOS-comments.patch +++ b/SOURCES/kvm-vga-Remove-some-should-be-done-in-BIOS-comments.patch @@ -1,13 +1,13 @@ -From 9397be4c801c71c84bc4ba6036efea32f5426c2e Mon Sep 17 00:00:00 2001 +From c5ee3f3aab59ff26b0fed770077a16714da9696e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann -Date: Fri, 29 Apr 2016 07:02:46 +0200 -Subject: [PATCH 1/6] vga: Remove some "should be done in BIOS" comments +Date: Thu, 28 Apr 2016 16:07:27 +0200 +Subject: [PATCH 22/27] vga: Remove some "should be done in BIOS" comments RH-Author: Gerd Hoffmann -Message-id: <1461913371-3145-2-git-send-email-kraxel@redhat.com> -Patchwork-id: 70301 -O-Subject: [virt-devel] [RHEL-7.2.z qemu-kvm PATCH 1/6] vga: Remove some "should be done in BIOS" comments -Bugzilla: 1331412 +Message-id: <1461859652-20918-2-git-send-email-kraxel@redhat.com> +Patchwork-id: 70292 +O-Subject: [virt-devel] [RHEL-7.3 qemu-kvm PATCH 1/6] vga: Remove some "should be done in BIOS" comments +Bugzilla: 1331413 RH-Acked-by: Miroslav Rezanina RH-Acked-by: Laszlo Ersek RH-Acked-by: Dr. David Alan Gilbert @@ -20,6 +20,7 @@ using the DISPI interface to initialize the card. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Gerd Hoffmann Reviewed-by: David Gibson +(cherry picked from commit ace89b8ff21cc3fb20986a334e54e6e6a1ccf729) Signed-off-by: Miroslav Rezanina --- hw/display/vga.c | 6 ++---- diff --git a/SOURCES/kvm-vga-add-sr_vbe-register-set.patch b/SOURCES/kvm-vga-add-sr_vbe-register-set.patch index 989709b..49bd9a5 100644 --- a/SOURCES/kvm-vga-add-sr_vbe-register-set.patch +++ b/SOURCES/kvm-vga-add-sr_vbe-register-set.patch @@ -1,13 +1,13 @@ -From eaf59089f691d89a0811fa355e9579fd44011dbe Mon Sep 17 00:00:00 2001 +From 40d4a0ec487abcde65d4175dde0c9dda45b570f9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 16 Jun 2016 15:30:11 +0200 -Subject: [PATCH] vga: add sr_vbe register set +Subject: [PATCH 2/2] vga: add sr_vbe register set RH-Author: Gerd Hoffmann Message-id: <1466091011-8095-2-git-send-email-kraxel@redhat.com> Patchwork-id: 70639 O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/1] vga: add sr_vbe register set -Bugzilla: 1347527 +Bugzilla: 1346982 RH-Acked-by: Laszlo Ersek RH-Acked-by: Stefan Hajnoczi RH-Acked-by: Dr. David Alan Gilbert diff --git a/SOURCES/kvm-vga-add-vbe_enabled-helper.patch b/SOURCES/kvm-vga-add-vbe_enabled-helper.patch index fb13245..fa400af 100644 --- a/SOURCES/kvm-vga-add-vbe_enabled-helper.patch +++ b/SOURCES/kvm-vga-add-vbe_enabled-helper.patch @@ -1,13 +1,13 @@ -From 0f24daf4c35cace529ae8441aa8b101ba53660ea Mon Sep 17 00:00:00 2001 +From 6e615e8fbbd979134868bcd63150365d48d12137 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann -Date: Fri, 29 Apr 2016 07:02:48 +0200 -Subject: [PATCH 3/6] vga: add vbe_enabled() helper +Date: Thu, 28 Apr 2016 16:07:29 +0200 +Subject: [PATCH 24/27] vga: add vbe_enabled() helper RH-Author: Gerd Hoffmann -Message-id: <1461913371-3145-4-git-send-email-kraxel@redhat.com> -Patchwork-id: 70303 -O-Subject: [virt-devel] [RHEL-7.2.z qemu-kvm PATCH 3/6] vga: add vbe_enabled() helper -Bugzilla: 1331412 +Message-id: <1461859652-20918-4-git-send-email-kraxel@redhat.com> +Patchwork-id: 70294 +O-Subject: [virt-devel] [RHEL-7.3 qemu-kvm PATCH 3/6] vga: add vbe_enabled() helper +Bugzilla: 1331413 RH-Acked-by: Miroslav Rezanina RH-Acked-by: Laszlo Ersek RH-Acked-by: Dr. David Alan Gilbert diff --git a/SOURCES/kvm-vga-factor-out-vga-register-setup.patch b/SOURCES/kvm-vga-factor-out-vga-register-setup.patch index 4314346..01f3261 100644 --- a/SOURCES/kvm-vga-factor-out-vga-register-setup.patch +++ b/SOURCES/kvm-vga-factor-out-vga-register-setup.patch @@ -1,13 +1,13 @@ -From c3eb11a92f0fa90fe2976c9c5ea59fe8ab862e77 Mon Sep 17 00:00:00 2001 +From 445ec835479fd06142078a59f1a88f2b30708930 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann -Date: Fri, 29 Apr 2016 07:02:49 +0200 -Subject: [PATCH 4/6] vga: factor out vga register setup +Date: Thu, 28 Apr 2016 16:07:30 +0200 +Subject: [PATCH 25/27] vga: factor out vga register setup RH-Author: Gerd Hoffmann -Message-id: <1461913371-3145-5-git-send-email-kraxel@redhat.com> -Patchwork-id: 70304 -O-Subject: [virt-devel] [RHEL-7.2.z qemu-kvm PATCH 4/6] vga: factor out vga register setup -Bugzilla: 1331412 +Message-id: <1461859652-20918-5-git-send-email-kraxel@redhat.com> +Patchwork-id: 70295 +O-Subject: [virt-devel] [RHEL-7.3 qemu-kvm PATCH 4/6] vga: factor out vga register setup +Bugzilla: 1331413 RH-Acked-by: Miroslav Rezanina RH-Acked-by: Laszlo Ersek RH-Acked-by: Dr. David Alan Gilbert diff --git a/SOURCES/kvm-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch b/SOURCES/kvm-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch deleted file mode 100644 index 13fd623..0000000 --- a/SOURCES/kvm-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 73714beab12fec056f3b38a7c2bc35a520405953 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 29 Apr 2016 07:02:47 +0200 -Subject: [PATCH 2/6] vga: fix banked access bounds checking (CVE-2016-3710) - -RH-Author: Gerd Hoffmann -Message-id: <1461913371-3145-3-git-send-email-kraxel@redhat.com> -Patchwork-id: 70302 -O-Subject: [virt-devel] [RHEL-7.2.z qemu-kvm PATCH 2/6] vga: fix banked access bounds checking (CVE-2016-3710) -Bugzilla: 1331412 -RH-Acked-by: Miroslav Rezanina -RH-Acked-by: Laszlo Ersek -RH-Acked-by: Dr. David Alan Gilbert - -vga allows banked access to video memory using the window at 0xa00000 -and it supports a different access modes with different address -calculations. - -The VBE bochs extentions support banked access too, using the -VBE_DISPI_INDEX_BANK register. The code tries to take the different -address calculations into account and applies different limits to -VBE_DISPI_INDEX_BANK depending on the current access mode. - -Which is probably effective in stopping misprogramming by accident. -But from a security point of view completely useless as an attacker -can easily change access modes after setting the bank register. - -Drop the bogus check, add range checks to vga_mem_{readb,writeb} -instead. - -Fixes: CVE-2016-3710 -Reported-by: Qinghao Tang -Signed-off-by: Gerd Hoffmann -Signed-off-by: Miroslav Rezanina ---- - hw/display/vga.c | 23 +++++++++++++++++------ - 1 file changed, 17 insertions(+), 6 deletions(-) - -diff --git a/hw/display/vga.c b/hw/display/vga.c -index 48dad03..ba171ba 100644 ---- a/hw/display/vga.c -+++ b/hw/display/vga.c -@@ -744,11 +744,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) - vbe_fixup_regs(s); - break; - case VBE_DISPI_INDEX_BANK: -- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { -- val &= (s->vbe_bank_mask >> 2); -- } else { -- val &= s->vbe_bank_mask; -- } -+ val &= s->vbe_bank_mask; - s->vbe_regs[s->vbe_index] = val; - s->bank_offset = (val << 16); - vga_update_memory_access(s); -@@ -847,13 +843,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr) - - if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) { - /* chain 4 mode : simplest access */ -+ assert(addr < s->vram_size); - ret = s->vram_ptr[addr]; - } else if (s->gr[VGA_GFX_MODE] & 0x10) { - /* odd/even mode (aka text mode mapping) */ - plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1); -- ret = s->vram_ptr[((addr & ~1) << 1) | plane]; -+ addr = ((addr & ~1) << 1) | plane; -+ if (addr >= s->vram_size) { -+ return 0xff; -+ } -+ ret = s->vram_ptr[addr]; - } else { - /* standard VGA latched access */ -+ if (addr * sizeof(uint32_t) >= s->vram_size) { -+ return 0xff; -+ } - s->latch = ((uint32_t *)s->vram_ptr)[addr]; - - if (!(s->gr[VGA_GFX_MODE] & 0x08)) { -@@ -910,6 +914,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) - plane = addr & 3; - mask = (1 << plane); - if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { -+ assert(addr < s->vram_size); - s->vram_ptr[addr] = val; - #ifdef DEBUG_VGA_MEM - printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr); -@@ -923,6 +928,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) - mask = (1 << plane); - if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { - addr = ((addr & ~1) << 1) | plane; -+ if (addr >= s->vram_size) { -+ return; -+ } - s->vram_ptr[addr] = val; - #ifdef DEBUG_VGA_MEM - printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr); -@@ -996,6 +1004,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) - mask = s->sr[VGA_SEQ_PLANE_WRITE]; - s->plane_updated |= mask; /* only used to detect font change */ - write_mask = mask16[mask]; -+ if (addr * sizeof(uint32_t) >= s->vram_size) { -+ return; -+ } - ((uint32_t *)s->vram_ptr)[addr] = - (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | - (val & write_mask); --- -1.8.3.1 - diff --git a/SOURCES/kvm-vga-fix-banked-access-bounds-checking-CVE-2016-xxxx.patch b/SOURCES/kvm-vga-fix-banked-access-bounds-checking-CVE-2016-xxxx.patch new file mode 100644 index 0000000..681e31b --- /dev/null +++ b/SOURCES/kvm-vga-fix-banked-access-bounds-checking-CVE-2016-xxxx.patch @@ -0,0 +1,108 @@ +From 27bca97bf22a55b1be7611e07c7592fcef5dd7cc Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 28 Apr 2016 16:07:28 +0200 +Subject: [PATCH 23/27] vga: fix banked access bounds checking (CVE-2016-xxxx). + +RH-Author: Gerd Hoffmann +Message-id: <1461859652-20918-3-git-send-email-kraxel@redhat.com> +Patchwork-id: 70293 +O-Subject: [virt-devel] [RHEL-7.3 qemu-kvm PATCH 2/6] vga: fix banked access bounds checking (CVE-2016-xxxx). +Bugzilla: 1331413 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Laszlo Ersek +RH-Acked-by: Dr. David Alan Gilbert + +vga allows banked access to video memory using the window at 0xa00000 +and it supports a different access modes with different address +calculations. + +The VBE bochs extentions support banked access too, using the +VBE_DISPI_INDEX_BANK register. The code tries to take the different +address calculations into account and applies different limits to +VBE_DISPI_INDEX_BANK depending on the current access mode. + +Which is probably effective in stopping misprogramming by accident. +But from a security point of view completely useless as an attacker +can easily change access modes after setting the bank register. + +Drop the bogus check, add range checks to vga_mem_{readb,writeb} +instead. + +Reported-by: Qinghao Tang +Signed-off-by: Gerd Hoffmann +Signed-off-by: Miroslav Rezanina +--- + hw/display/vga.c | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/hw/display/vga.c b/hw/display/vga.c +index 48dad03..ba171ba 100644 +--- a/hw/display/vga.c ++++ b/hw/display/vga.c +@@ -744,11 +744,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) + vbe_fixup_regs(s); + break; + case VBE_DISPI_INDEX_BANK: +- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { +- val &= (s->vbe_bank_mask >> 2); +- } else { +- val &= s->vbe_bank_mask; +- } ++ val &= s->vbe_bank_mask; + s->vbe_regs[s->vbe_index] = val; + s->bank_offset = (val << 16); + vga_update_memory_access(s); +@@ -847,13 +843,21 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr) + + if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) { + /* chain 4 mode : simplest access */ ++ assert(addr < s->vram_size); + ret = s->vram_ptr[addr]; + } else if (s->gr[VGA_GFX_MODE] & 0x10) { + /* odd/even mode (aka text mode mapping) */ + plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1); +- ret = s->vram_ptr[((addr & ~1) << 1) | plane]; ++ addr = ((addr & ~1) << 1) | plane; ++ if (addr >= s->vram_size) { ++ return 0xff; ++ } ++ ret = s->vram_ptr[addr]; + } else { + /* standard VGA latched access */ ++ if (addr * sizeof(uint32_t) >= s->vram_size) { ++ return 0xff; ++ } + s->latch = ((uint32_t *)s->vram_ptr)[addr]; + + if (!(s->gr[VGA_GFX_MODE] & 0x08)) { +@@ -910,6 +914,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) + plane = addr & 3; + mask = (1 << plane); + if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { ++ assert(addr < s->vram_size); + s->vram_ptr[addr] = val; + #ifdef DEBUG_VGA_MEM + printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr); +@@ -923,6 +928,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) + mask = (1 << plane); + if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { + addr = ((addr & ~1) << 1) | plane; ++ if (addr >= s->vram_size) { ++ return; ++ } + s->vram_ptr[addr] = val; + #ifdef DEBUG_VGA_MEM + printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr); +@@ -996,6 +1004,9 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val) + mask = s->sr[VGA_SEQ_PLANE_WRITE]; + s->plane_updated |= mask; /* only used to detect font change */ + write_mask = mask16[mask]; ++ if (addr * sizeof(uint32_t) >= s->vram_size) { ++ return; ++ } + ((uint32_t *)s->vram_ptr)[addr] = + (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | + (val & write_mask); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch b/SOURCES/kvm-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch index 131c165..2cbc550 100644 --- a/SOURCES/kvm-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch +++ b/SOURCES/kvm-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch @@ -1,13 +1,13 @@ -From d4916c5677937634c50737ac3caa9b6823789f4f Mon Sep 17 00:00:00 2001 +From 3c18025a495a2c105c2c33051ece0f3525d1e0c4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann -Date: Fri, 29 Apr 2016 07:02:51 +0200 -Subject: [PATCH 6/6] vga: make sure vga register setup for vbe stays intact. +Date: Thu, 28 Apr 2016 16:07:32 +0200 +Subject: [PATCH 27/27] vga: make sure vga register setup for vbe stays intact. RH-Author: Gerd Hoffmann -Message-id: <1461913371-3145-7-git-send-email-kraxel@redhat.com> -Patchwork-id: 70306 -O-Subject: [virt-devel] [RHEL-7.2.z qemu-kvm PATCH 6/6] vga: make sure vga register setup for vbe stays intact. -Bugzilla: 1331412 +Message-id: <1461859652-20918-7-git-send-email-kraxel@redhat.com> +Patchwork-id: 70297 +O-Subject: [virt-devel] [RHEL-7.3 qemu-kvm PATCH 6/6] vga: make sure vga register setup for vbe stays intact. +Bugzilla: 1331413 RH-Acked-by: Miroslav Rezanina RH-Acked-by: Laszlo Ersek RH-Acked-by: Dr. David Alan Gilbert diff --git a/SOURCES/kvm-vga-update-vga-register-setup-on-vbe-changes.patch b/SOURCES/kvm-vga-update-vga-register-setup-on-vbe-changes.patch index 5c5a293..648f3dd 100644 --- a/SOURCES/kvm-vga-update-vga-register-setup-on-vbe-changes.patch +++ b/SOURCES/kvm-vga-update-vga-register-setup-on-vbe-changes.patch @@ -1,13 +1,13 @@ -From 1dfb069237e2ddf979407841a2907cd332017924 Mon Sep 17 00:00:00 2001 +From 6bf28a8a9e2e6d6505f2a906b7fc532427037c5f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann -Date: Fri, 29 Apr 2016 07:02:50 +0200 -Subject: [PATCH 5/6] vga: update vga register setup on vbe changes +Date: Thu, 28 Apr 2016 16:07:31 +0200 +Subject: [PATCH 26/27] vga: update vga register setup on vbe changes RH-Author: Gerd Hoffmann -Message-id: <1461913371-3145-6-git-send-email-kraxel@redhat.com> -Patchwork-id: 70305 -O-Subject: [virt-devel] [RHEL-7.2.z qemu-kvm PATCH 5/6] vga: update vga register setup on vbe changes -Bugzilla: 1331412 +Message-id: <1461859652-20918-6-git-send-email-kraxel@redhat.com> +Patchwork-id: 70296 +O-Subject: [virt-devel] [RHEL-7.3 qemu-kvm PATCH 5/6] vga: update vga register setup on vbe changes +Bugzilla: 1331413 RH-Acked-by: Miroslav Rezanina RH-Acked-by: Laszlo Ersek RH-Acked-by: Dr. David Alan Gilbert diff --git a/SOURCES/kvm-virtio-error-out-if-guest-exceeds-virtqueue-size.patch b/SOURCES/kvm-virtio-error-out-if-guest-exceeds-virtqueue-size.patch index 7444829..85dee6d 100644 --- a/SOURCES/kvm-virtio-error-out-if-guest-exceeds-virtqueue-size.patch +++ b/SOURCES/kvm-virtio-error-out-if-guest-exceeds-virtqueue-size.patch @@ -1,7 +1,7 @@ -From 328d99710a005b9042c4d4c423f3f5a21f0e8ead Mon Sep 17 00:00:00 2001 +From acb67d9c43f3921861eebbabb447a85644e99320 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 25 Jul 2016 12:55:36 +0200 -Subject: [PATCH] virtio: error out if guest exceeds virtqueue size +Subject: [PATCH 2/2] virtio: error out if guest exceeds virtqueue size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -10,7 +10,7 @@ RH-Author: Stefan Hajnoczi Message-id: <1469451336-20117-2-git-send-email-stefanha@redhat.com> Patchwork-id: 71428 O-Subject: [virt-devel] [RHEL-7.3 EMBARGOED qemu-kvm PATCH 1/1] virtio: error out if guest exceeds virtqueue size -Bugzilla: 1359728 +Bugzilla: 1359729 RH-Acked-by: Thomas Huth RH-Acked-by: Marc-André Lureau RH-Acked-by: Laszlo Ersek diff --git a/SOURCES/kvm-virtio-recalculate-vq-inuse-after-migration.patch b/SOURCES/kvm-virtio-recalculate-vq-inuse-after-migration.patch new file mode 100644 index 0000000..4bb6852 --- /dev/null +++ b/SOURCES/kvm-virtio-recalculate-vq-inuse-after-migration.patch @@ -0,0 +1,73 @@ +From 4d0430b1f847d672a39c76e6567bb5e88bc33c78 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Fri, 16 Sep 2016 08:38:18 +0200 +Subject: [PATCH] virtio: recalculate vq->inuse after migration + +RH-Author: Stefan Hajnoczi +Message-id: <1474015098-11019-2-git-send-email-stefanha@redhat.com> +Patchwork-id: 72372 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 1/1] virtio: recalculate vq->inuse after migration +Bugzilla: 1376542 +RH-Acked-by: Paolo Bonzini +RH-Acked-by: Markus Armbruster +RH-Acked-by: Miroslav Rezanina + +The vq->inuse field is not migrated. Many devices don't hold +VirtQueueElements across migration so it doesn't matter that vq->inuse +starts at 0 on the destination QEMU. + +At least virtio-serial, virtio-blk, and virtio-balloon migrate while +holding VirtQueueElements. For these devices we need to recalculate +vq->inuse upon load so the value is correct. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Stefan Hajnoczi +Reviewed-by: Michael S. Tsirkin +Reviewed-by: Cornelia Huck +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit bccdef6b1a204db0f41ffb6e24ce373e4d7890d4) +Signed-off-by: Miroslav Rezanina + +Conflicts: + + hw/virtio/virtio.c + + Downstream does not have the vq->used_idx field which was added + upstream as a performance optimization reducing guest memory accesses. + Replace vq->used_idx with vring_used_idx(&vdev->vq[i]). + +Signed-off-by: Stefan Hajnoczi +--- + hw/virtio/virtio.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index e67337b..0df4ed3 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -932,6 +932,21 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) + vdev->vq[i].last_avail_idx, nheads); + return -1; + } ++ ++ /* ++ * Some devices migrate VirtQueueElements that have been popped ++ * from the avail ring but not yet returned to the used ring. ++ */ ++ vdev->vq[i].inuse = vdev->vq[i].last_avail_idx - ++ vring_used_idx(&vdev->vq[i]); ++ if (vdev->vq[i].inuse > vdev->vq[i].vring.num) { ++ error_report("VQ %d size 0x%x < last_avail_idx 0x%x - " ++ "used_idx 0x%x", ++ i, vdev->vq[i].vring.num, ++ vdev->vq[i].last_avail_idx, ++ vring_used_idx(&vdev->vq[i])); ++ return -1; ++ } + } else if (vdev->vq[i].last_avail_idx) { + error_report("VQ %d address 0x0 " + "inconsistent with Host index 0x%x", +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-scsi-Prevent-assertion-on-missed-events.patch b/SOURCES/kvm-virtio-scsi-Prevent-assertion-on-missed-events.patch new file mode 100644 index 0000000..0f0cc02 --- /dev/null +++ b/SOURCES/kvm-virtio-scsi-Prevent-assertion-on-missed-events.patch @@ -0,0 +1,46 @@ +From 3fdd5ce3ece26d5fd0d7702e08167bf5e513f620 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 18 Apr 2016 02:50:12 +0200 +Subject: [PATCH 01/10] virtio-scsi: Prevent assertion on missed events + +RH-Author: Fam Zheng +Message-id: <1460947812-5704-1-git-send-email-famz@redhat.com> +Patchwork-id: 70202 +O-Subject: [RHEL-7.3 qemu-kvm PATCH] virtio-scsi: Prevent assertion on missed events +Bugzilla: 1312289 +RH-Acked-by: Thomas Huth +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Paolo Bonzini + +From: Eric Farman + +In some cases, an unplug can cause events to be dropped, which +leads to an assertion failure when preparing to notify the guest +kernel. + +Signed-off-by: Eric Farman +Cc: qemu-stable@nongnu.org +Signed-off-by: Paolo Bonzini +(cherry picked from commit 49fb65c7f985baa56d2964e0a85c1f098e3e2a9d) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + hw/scsi/virtio-scsi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c +index 8232fc9..808eb54 100644 +--- a/hw/scsi/virtio-scsi.c ++++ b/hw/scsi/virtio-scsi.c +@@ -530,7 +530,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, + evt->event = event; + evt->reason = reason; + if (!dev) { +- assert(event == VIRTIO_SCSI_T_NO_EVENT); ++ assert(event == VIRTIO_SCSI_T_EVENTS_MISSED); + } else { + evt->lun[0] = 1; + evt->lun[1] = dev->id; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-virtio-validate-the-existence-of-handle_output-befor.patch b/SOURCES/kvm-virtio-validate-the-existence-of-handle_output-befor.patch new file mode 100644 index 0000000..7927554 --- /dev/null +++ b/SOURCES/kvm-virtio-validate-the-existence-of-handle_output-befor.patch @@ -0,0 +1,59 @@ +From 612017cc4834cd5eabc12afc7dd6cebf890b42e5 Mon Sep 17 00:00:00 2001 +From: Xiao Wang +Date: Fri, 19 Aug 2016 09:24:25 +0200 +Subject: [PATCH] virtio: validate the existence of handle_output before + calling it + +RH-Author: Xiao Wang +Message-id: <1471598665-23846-1-git-send-email-jasowang@redhat.com> +Patchwork-id: 72021 +O-Subject: [RHEL7.3 qemu-kvm PATCH] virtio: validate the existence of handle_output before calling it +Bugzilla: 1367040 +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Fam Zheng +RH-Acked-by: Pankaj Gupta + +Bugzilla: 1367040 +Brew Build: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=11620539 +Test status: Tested by myself. + +We don't validate the existence of handle_output which may let a buggy +guest to trigger a SIGSEV easily. E.g: + +1) write 10 to queue_sel to a virtio net device with only 1 queue +2) setup an arbitrary pfn +3) then notify queue 10 + +Fixing this by validating the existence of handle_output before. + +Cc: qemu-stable@nongnu.org +Cc: Michael S. Tsirkin +Signed-off-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Reviewed-by: Don Koch +Reviewed-by: Fam Zheng +(cherry picked from commit 9e0f5b8108e248b78444c9a2ec41a8309825736c) +Signed-off-by: Miroslav Rezanina +--- + hw/virtio/virtio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index a861870..e67337b 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -692,8 +692,9 @@ int virtio_queue_get_id(VirtQueue *vq) + + void virtio_queue_notify_vq(VirtQueue *vq) + { +- if (vq->vring.desc) { ++ if (vq->vring.desc && vq->handle_output) { + VirtIODevice *vdev = vq->vdev; ++ + trace_virtio_queue_notify(vdev, vq - vdev->vq, vq); + vq->handle_output(vdev, vq); + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Check-descriptor-file-length-when-reading-it.patch b/SOURCES/kvm-vmdk-Check-descriptor-file-length-when-reading-it.patch new file mode 100644 index 0000000..0d97d1a --- /dev/null +++ b/SOURCES/kvm-vmdk-Check-descriptor-file-length-when-reading-it.patch @@ -0,0 +1,56 @@ +From 86c71987b64382e1177f86e6bc00bfc19e20082d Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:18 +0100 +Subject: [PATCH 05/18] vmdk: Check descriptor file length when reading it + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-6-git-send-email-famz@redhat.com> +Patchwork-id: 69171 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 05/18] vmdk: Check descriptor file length when reading it +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +Since a too small file cannot be a valid VMDK image, and also since the +buffer's first 4 bytes will be unconditionally examined by +vmdk_open_sparse, let's error out the small file case to be clear. + +Signed-off-by: Fam Zheng +Reviewed-by: Max Reitz +Reviewed-by: Markus Armbruster +Reviewed-by: Don Koch +Message-id: 1417649314-13704-5-git-send-email-famz@redhat.com +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 03c3359dfc490eaf922f88955d6a8cc51a37ce92) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 3dfbd41..db3cdc0 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -559,6 +559,14 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset, + return NULL; + } + ++ if (size < 4) { ++ /* Both descriptor file and sparse image must be much larger than 4 ++ * bytes, also callers of vmdk_read_desc want to compare the first 4 ++ * bytes with VMDK4_MAGIC, let's error out if less is read. */ ++ error_setg(errp, "File is too small, not a valid image"); ++ return NULL; ++ } ++ + size = MIN(size, (1 << 20) - 1); /* avoid unbounded allocation */ + buf = g_malloc(size + 1); + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Clean-up-descriptor-file-reading.patch b/SOURCES/kvm-vmdk-Clean-up-descriptor-file-reading.patch new file mode 100644 index 0000000..cb60e19 --- /dev/null +++ b/SOURCES/kvm-vmdk-Clean-up-descriptor-file-reading.patch @@ -0,0 +1,60 @@ +From 2aa26696846adf25a41fa082f4d42c98b2b05fe3 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:17 +0100 +Subject: [PATCH 04/18] vmdk: Clean up descriptor file reading + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-5-git-send-email-famz@redhat.com> +Patchwork-id: 69170 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 04/18] vmdk: Clean up descriptor file reading +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +Zeroing a buffer that will be filled right after is not necessary, and +allocating a power of two + 1 is naughty. + +Suggested-by: Markus Armbruster +Signed-off-by: Fam Zheng +Reviewed-by: Don Koch +Reviewed-by: Markus Armbruster +Reviewed-by: Max Reitz +Message-id: 1417649314-13704-4-git-send-email-famz@redhat.com +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 73b7bcad439e0edaced05049897090cc10d84b5b) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 3f34abf..3dfbd41 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -559,8 +559,8 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset, + return NULL; + } + +- size = MIN(size, 1 << 20); /* avoid unbounded allocation */ +- buf = g_malloc0(size + 1); ++ size = MIN(size, (1 << 20) - 1); /* avoid unbounded allocation */ ++ buf = g_malloc(size + 1); + + ret = bdrv_pread(file, desc_offset, buf, size); + if (ret < 0) { +@@ -568,6 +568,7 @@ static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset, + g_free(buf); + return NULL; + } ++ buf[ret] = 0; + + return buf; + } +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Create-streamOptimized-as-version-3.patch b/SOURCES/kvm-vmdk-Create-streamOptimized-as-version-3.patch new file mode 100644 index 0000000..4df8e5a --- /dev/null +++ b/SOURCES/kvm-vmdk-Create-streamOptimized-as-version-3.patch @@ -0,0 +1,51 @@ +From 7777177c3c7291ff5c4b24040b075a1bd1c1db77 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:29 +0100 +Subject: [PATCH 16/18] vmdk: Create streamOptimized as version 3 + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-17-git-send-email-famz@redhat.com> +Patchwork-id: 69182 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 16/18] vmdk: Create streamOptimized as version 3 +Bugzilla: 1299116 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299116 + +VMware products accept only version 3 for streamOptimized, let's bump +the version. + +Reported-by: Radoslav Gerganov +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit d62d9dc4b814950dcc8bd261a3e2e9300d9065e6) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 7009660..7b3e397 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -1658,7 +1658,13 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, + } + magic = cpu_to_be32(VMDK4_MAGIC); + memset(&header, 0, sizeof(header)); +- header.version = zeroed_grain ? 2 : 1; ++ if (compress) { ++ header.version = 3; ++ } else if (zeroed_grain) { ++ header.version = 2; ++ } else { ++ header.version = 1; ++ } + header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT + | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0) + | (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0); +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Fix-calculation-of-block-status-s-offset.patch b/SOURCES/kvm-vmdk-Fix-calculation-of-block-status-s-offset.patch new file mode 100644 index 0000000..ed9910c --- /dev/null +++ b/SOURCES/kvm-vmdk-Fix-calculation-of-block-status-s-offset.patch @@ -0,0 +1,60 @@ +From 0cdb7038a7027cbb63c820e60bb34abd191ac85f Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:31 +0100 +Subject: [PATCH 18/18] vmdk: Fix calculation of block status's offset + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-19-git-send-email-famz@redhat.com> +Patchwork-id: 69184 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 18/18] vmdk: Fix calculation of block status's offset +Bugzilla: 1299116 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +"offset" is the offset of cluster and sector_num doesn't necessarily +refer to the start of it, it should add index_in_cluster. + +Signed-off-by: Fam Zheng +Message-id: 1453780743-16806-12-git-send-email-famz@redhat.com +Reviewed-by: Max Reitz +Signed-off-by: Max Reitz +(cherry picked from commit d0a18f10251f515c86dcaec5bdf979a4e07fafc5) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index b0c312b..b4f0d44 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -1275,6 +1275,7 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs, + 0, 0); + qemu_co_mutex_unlock(&s->lock); + ++ index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num); + switch (ret) { + case VMDK_ERROR: + ret = -EIO; +@@ -1288,13 +1289,14 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs, + case VMDK_OK: + ret = BDRV_BLOCK_DATA; + if (extent->file == bs->file && !extent->compressed) { +- ret |= BDRV_BLOCK_OFFSET_VALID | offset; ++ ret |= BDRV_BLOCK_OFFSET_VALID; ++ ret |= (offset + (index_in_cluster << BDRV_SECTOR_BITS)) ++ & BDRV_BLOCK_OFFSET_MASK; + } + + break; + } + +- index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num); + n = extent->cluster_sectors - index_in_cluster; + if (n > nb_sectors) { + n = nb_sectors; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Fix-comment-to-match-code-of-extent-lines.patch b/SOURCES/kvm-vmdk-Fix-comment-to-match-code-of-extent-lines.patch new file mode 100644 index 0000000..85330ef --- /dev/null +++ b/SOURCES/kvm-vmdk-Fix-comment-to-match-code-of-extent-lines.patch @@ -0,0 +1,56 @@ +From ad76b22d2d96499bbbd1172f347b4ec8a2327c7d Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:16 +0100 +Subject: [PATCH 03/18] vmdk: Fix comment to match code of extent lines + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-4-git-send-email-famz@redhat.com> +Patchwork-id: 69169 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 03/18] vmdk: Fix comment to match code of extent lines +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +commit 04d542c8b (vmdk: support vmfs files) added support of VMFS extent +type but the comment above the changed code is left out. Update the +comment so they are consistent. + +Signed-off-by: Fam Zheng +Reviewed-by: Max Reitz +Reviewed-by: Markus Armbruster +Reviewed-by: Don Koch +Message-id: 1417649314-13704-3-git-send-email-famz@redhat.com +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 8a3e0bc370de9274170b82f48b0393204c3fb43b) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index a9f5bab..3f34abf 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -788,10 +788,12 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, + VmdkExtent *extent; + + while (*p) { +- /* parse extent line: ++ /* parse extent line in one of below formats: ++ * + * RW [size in sectors] FLAT "file-name.vmdk" OFFSET +- * or + * RW [size in sectors] SPARSE "file-name.vmdk" ++ * RW [size in sectors] VMFS "file-name.vmdk" ++ * RW [size in sectors] VMFSSPARSE "file-name.vmdk" + */ + flat_offset = -1; + ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Fix-converting-to-streamOptimized.patch b/SOURCES/kvm-vmdk-Fix-converting-to-streamOptimized.patch new file mode 100644 index 0000000..ab886e7 --- /dev/null +++ b/SOURCES/kvm-vmdk-Fix-converting-to-streamOptimized.patch @@ -0,0 +1,65 @@ +From b72998772910dbd04c86a2332b1c69ac1afc7a9e Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:30 +0100 +Subject: [PATCH 17/18] vmdk: Fix converting to streamOptimized + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-18-git-send-email-famz@redhat.com> +Patchwork-id: 69183 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 17/18] vmdk: Fix converting to streamOptimized +Bugzilla: 1299116 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299116 + +Commit d62d9dc4b8 lifted streamOptimized images's version to 3, but we +now refuse to open version 3 images read-write. We need to make +streamOptimized an exception to allow converting to it. This fixes the +accidentally broken iotests case 059 for the same reason. + +Signed-off-by: Fam Zheng +Signed-off-by: Kevin Wolf +Signed-off-by: Max Reitz +(cherry picked from commit 3db1d98a20262228373bb973ca62b1ab64b29af4) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 7b3e397..b0c312b 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -592,6 +592,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, + VmdkExtent *extent; + BDRVVmdkState *s = bs->opaque; + int64_t l1_backup_offset = 0; ++ bool compressed; + + ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); + if (ret < 0) { +@@ -666,6 +667,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, + header = footer.header; + } + ++ compressed = ++ le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; + if (le32_to_cpu(header.version) > 3) { + char buf[64]; + snprintf(buf, sizeof(buf), "VMDK version %" PRId32, +@@ -673,7 +676,8 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, + error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, + bs->device_name, "vmdk", buf); + return -ENOTSUP; +- } else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) { ++ } else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR) && ++ !compressed) { + /* VMware KB 2064959 explains that version 3 added support for + * persistent changed block tracking (CBT), and backup software can + * read it as version=1 if it doesn't care about the changed area +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Fix-index_in_cluster-calculation-in-vmdk_co_get.patch b/SOURCES/kvm-vmdk-Fix-index_in_cluster-calculation-in-vmdk_co_get.patch new file mode 100644 index 0000000..311534c --- /dev/null +++ b/SOURCES/kvm-vmdk-Fix-index_in_cluster-calculation-in-vmdk_co_get.patch @@ -0,0 +1,65 @@ +From 32791762f04b3342e9b10d1f553326cd01ea451f Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:26 +0100 +Subject: [PATCH 13/18] vmdk: Fix index_in_cluster calculation in + vmdk_co_get_block_status + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-14-git-send-email-famz@redhat.com> +Patchwork-id: 69179 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 13/18] vmdk: Fix index_in_cluster calculation in vmdk_co_get_block_status +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +It has the similar issue with b1649fae49a8. Since the calculation +is repeated for a few times already, introduce a function so it can be +reused. + +Signed-off-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 61f0ed1d54601b91b8195c1a30d7046f83283b40) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index dd8b638..10c08f3 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -1242,6 +1242,17 @@ static VmdkExtent *find_extent(BDRVVmdkState *s, + return NULL; + } + ++static inline uint64_t vmdk_find_index_in_cluster(VmdkExtent *extent, ++ int64_t sector_num) ++{ ++ uint64_t index_in_cluster, extent_begin_sector, extent_relative_sector_num; ++ ++ extent_begin_sector = extent->end_sector - extent->sectors; ++ extent_relative_sector_num = sector_num - extent_begin_sector; ++ index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; ++ return index_in_cluster; ++} ++ + static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, int *pnum) + { +@@ -1279,7 +1290,7 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs, + break; + } + +- index_in_cluster = sector_num % extent->cluster_sectors; ++ index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num); + n = extent->cluster_sectors - index_in_cluster; + if (n > nb_sectors) { + n = nb_sectors; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Fix-next_cluster_sector-for-compressed-write.patch b/SOURCES/kvm-vmdk-Fix-next_cluster_sector-for-compressed-write.patch new file mode 100644 index 0000000..044ab7a --- /dev/null +++ b/SOURCES/kvm-vmdk-Fix-next_cluster_sector-for-compressed-write.patch @@ -0,0 +1,70 @@ +From 47886bf3b19f06d0a5255d9656d1c02800baddd0 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:25 +0100 +Subject: [PATCH 12/18] vmdk: Fix next_cluster_sector for compressed write + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-13-git-send-email-famz@redhat.com> +Patchwork-id: 69178 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 12/18] vmdk: Fix next_cluster_sector for compressed write +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +This fixes the bug introduced by commit c6ac36e (vmdk: Optimize cluster +allocation). + +Sometimes, write_len could be larger than cluster size, because it +contains both data and marker. We must advance next_cluster_sector in +this case, otherwise the image gets corrupted. + +Cc: qemu-stable@nongnu.org +Reported-by: Antoni Villalonga +Signed-off-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 5e82a31eb967db135fc4e688b134fb0972d62de3) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 3810d75..dd8b638 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -1297,6 +1297,8 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, + uLongf buf_len; + const uint8_t *write_buf = buf; + int write_len = nb_sectors * 512; ++ int64_t write_offset; ++ int64_t write_end_sector; + + if (extent->compressed) { + if (!extent->has_marker) { +@@ -1315,10 +1317,14 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, + write_buf = (uint8_t *)data; + write_len = buf_len + sizeof(VmdkGrainMarker); + } +- ret = bdrv_pwrite(extent->file, +- cluster_offset + offset_in_cluster, +- write_buf, +- write_len); ++ write_offset = cluster_offset + offset_in_cluster, ++ ret = bdrv_pwrite(extent->file, write_offset, write_buf, write_len); ++ ++ write_end_sector = DIV_ROUND_UP(write_offset + write_len, BDRV_SECTOR_SIZE); ++ ++ extent->next_cluster_sector = MAX(extent->next_cluster_sector, ++ write_end_sector); ++ + if (ret != write_len) { + ret = ret < 0 ? ret : -EIO; + goto out; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Fix-next_cluster_sector-for-compressed-write2.patch b/SOURCES/kvm-vmdk-Fix-next_cluster_sector-for-compressed-write2.patch new file mode 100644 index 0000000..f926460 --- /dev/null +++ b/SOURCES/kvm-vmdk-Fix-next_cluster_sector-for-compressed-write2.patch @@ -0,0 +1,55 @@ +From bc048d2d5f362757fa0bf51add81d92ec19ad161 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:28 +0100 +Subject: [PATCH 15/18] vmdk: Fix next_cluster_sector for compressed write + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-16-git-send-email-famz@redhat.com> +Patchwork-id: 69181 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 15/18] vmdk: Fix next_cluster_sector for compressed write +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +From: Radoslav Gerganov + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +When the VMDK is streamOptimized (or compressed), the +next_cluster_sector must not be incremented by a fixed number of +sectors. Instead of this, it must be rounded up to the next consecutive +sector. Fixing this results in much smaller compressed images. + +Signed-off-by: Radoslav Gerganov +Reviewed-by: Fam Zheng +Signed-off-by: Kevin Wolf +(cherry picked from commit 3efffc3292d94271a15b1606b4a56adf6c6f04ed) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index cb5255c..7009660 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -1333,8 +1333,12 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, + + write_end_sector = DIV_ROUND_UP(write_offset + write_len, BDRV_SECTOR_SIZE); + +- extent->next_cluster_sector = MAX(extent->next_cluster_sector, +- write_end_sector); ++ if (extent->compressed) { ++ extent->next_cluster_sector = write_end_sector; ++ } else { ++ extent->next_cluster_sector = MAX(extent->next_cluster_sector, ++ write_end_sector); ++ } + + if (ret != write_len) { + ret = ret < 0 ? ret : -EIO; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Leave-bdi-intact-if-ENOTSUP-in-vmdk_get_info.patch b/SOURCES/kvm-vmdk-Leave-bdi-intact-if-ENOTSUP-in-vmdk_get_info.patch new file mode 100644 index 0000000..9566d00 --- /dev/null +++ b/SOURCES/kvm-vmdk-Leave-bdi-intact-if-ENOTSUP-in-vmdk_get_info.patch @@ -0,0 +1,74 @@ +From 824614c344ceeb60dd27b38cfdb190471b6a2ef9 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:14 +0100 +Subject: [PATCH 01/18] vmdk: Leave bdi intact if -ENOTSUP in vmdk_get_info + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-2-git-send-email-famz@redhat.com> +Patchwork-id: 69167 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 01/18] vmdk: Leave bdi intact if -ENOTSUP in vmdk_get_info +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +When extent types don't match, we return -ENOTSUP. In this case, be +polite to the caller and don't modify bdi. + +Signed-off-by: Fam Zheng +Reviewed-by: Max Reitz +Message-id: 1415938161-16217-1-git-send-email-famz@redhat.com +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 5f58330790b72c4705b373ee0646fb3adf800b4e) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 6b015ab..fa53d2f 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -2137,23 +2137,29 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs) + return spec_info; + } + ++static bool vmdk_extents_type_eq(const VmdkExtent *a, const VmdkExtent *b) ++{ ++ return a->flat == b->flat && ++ a->compressed == b->compressed && ++ (a->flat || a->cluster_sectors == b->cluster_sectors); ++} ++ + static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) + { + int i; + BDRVVmdkState *s = bs->opaque; + assert(s->num_extents); +- bdi->needs_compressed_writes = s->extents[0].compressed; +- if (!s->extents[0].flat) { +- bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS; +- } ++ + /* See if we have multiple extents but they have different cases */ + for (i = 1; i < s->num_extents; i++) { +- if (bdi->needs_compressed_writes != s->extents[i].compressed || +- (bdi->cluster_size && bdi->cluster_size != +- s->extents[i].cluster_sectors << BDRV_SECTOR_BITS)) { ++ if (!vmdk_extents_type_eq(&s->extents[0], &s->extents[i])) { + return -ENOTSUP; + } + } ++ bdi->needs_compressed_writes = s->extents[0].compressed; ++ if (!s->extents[0].flat) { ++ bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS; ++ } + return 0; + } + +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Remove-unnecessary-initialization.patch b/SOURCES/kvm-vmdk-Remove-unnecessary-initialization.patch new file mode 100644 index 0000000..2d5267e --- /dev/null +++ b/SOURCES/kvm-vmdk-Remove-unnecessary-initialization.patch @@ -0,0 +1,49 @@ +From aea042fc3e0a8454edb4e9884635af63128b15d3 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:19 +0100 +Subject: [PATCH 06/18] vmdk: Remove unnecessary initialization + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-7-git-send-email-famz@redhat.com> +Patchwork-id: 69172 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 06/18] vmdk: Remove unnecessary initialization +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +It will be assigned to the return value of vmdk_read_desc. + +Suggested-by: Markus Armbruster +Signed-off-by: Fam Zheng +Reviewed-by: Markus Armbruster +Reviewed-by: Don Koch +Reviewed-by: Max Reitz +Message-id: 1417649314-13704-6-git-send-email-famz@redhat.com +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 9aeecbbc62ce52a94b2621a0d53567b5d4ed915d) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index db3cdc0..69d8a6e 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -916,7 +916,7 @@ exit: + static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, + Error **errp) + { +- char *buf = NULL; ++ char *buf; + int ret; + BDRVVmdkState *s = bs->opaque; + uint32_t magic; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Set-errp-on-failures-in-vmdk_open_vmdk4.patch b/SOURCES/kvm-vmdk-Set-errp-on-failures-in-vmdk_open_vmdk4.patch new file mode 100644 index 0000000..af942ef --- /dev/null +++ b/SOURCES/kvm-vmdk-Set-errp-on-failures-in-vmdk_open_vmdk4.patch @@ -0,0 +1,62 @@ +From 005308f5b469f749980310be141315e8bd46556f Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:20 +0100 +Subject: [PATCH 07/18] vmdk: Set errp on failures in vmdk_open_vmdk4 + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-8-git-send-email-famz@redhat.com> +Patchwork-id: 69173 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 07/18] vmdk: Set errp on failures in vmdk_open_vmdk4 +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +Reported-by: Markus Armbruster +Signed-off-by: Fam Zheng +Reviewed-by: Markus Armbruster +Reviewed-by: Don Koch +Reviewed-by: Max Reitz +Message-id: 1417649314-13704-7-git-send-email-famz@redhat.com +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit d899d2e248b900c53dd9081bde9f110e05747433) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 69d8a6e..1247ea4 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -647,6 +647,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, + bs->file->total_sectors * 512 - 1536, + &footer, sizeof(footer)); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to read footer"); + return ret; + } + +@@ -658,6 +659,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, + le32_to_cpu(footer.eos_marker.size) != 0 || + le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM) + { ++ error_setg(errp, "Invalid footer"); + return -EINVAL; + } + +@@ -688,6 +690,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, + l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt) + * le64_to_cpu(header.granularity); + if (l1_entry_sectors == 0) { ++ error_setg(errp, "L1 entry size is invalid"); + return -EINVAL; + } + l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1) +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Use-g_random_int-to-generate-CID.patch b/SOURCES/kvm-vmdk-Use-g_random_int-to-generate-CID.patch new file mode 100644 index 0000000..0294a48 --- /dev/null +++ b/SOURCES/kvm-vmdk-Use-g_random_int-to-generate-CID.patch @@ -0,0 +1,73 @@ +From bf9dd867ef8d4164685cac6451e88b6c32b190b1 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:15 +0100 +Subject: [PATCH 02/18] vmdk: Use g_random_int to generate CID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-3-git-send-email-famz@redhat.com> +Patchwork-id: 69168 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 02/18] vmdk: Use g_random_int to generate CID +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +This replaces two "time(NULL)" invocations with "g_random_int()". +According to VMDK spec, CID "is a random 32‐bit value updated the first +time the content of the virtual disk is modified after the virtual disk +is opened". Using "seconds since epoch" is just a "lame way" to generate +it, and not completely safe because of the low precision. + +Suggested-by: Markus Armbruster +Signed-off-by: Fam Zheng +Reviewed-by: Markus Armbruster +Reviewed-by: Don Koch +Reviewed-by: Max Reitz +Message-id: 1417649314-13704-2-git-send-email-famz@redhat.com +Signed-off-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit e5dc64b8ff09cc4c186273e4461c7479739db2ae) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index fa53d2f..a9f5bab 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -28,6 +28,7 @@ + #include "qemu/module.h" + #include "migration/migration.h" + #include ++#include + + #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') + #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') +@@ -1540,7 +1541,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, + /* update CID on the first write every time the virtual disk is + * opened */ + if (!s->cid_updated) { +- ret = vmdk_write_cid(bs, time(NULL)); ++ ret = vmdk_write_cid(bs, g_random_int()); + if (ret < 0) { + return ret; + } +@@ -1927,7 +1928,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, + } + /* generate descriptor file */ + desc = g_strdup_printf(desc_template, +- (uint32_t)time(NULL), ++ g_random_int(), + parent_cid, + fmt, + parent_desc_line, +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Use-vmdk_find_index_in_cluster-everywhere.patch b/SOURCES/kvm-vmdk-Use-vmdk_find_index_in_cluster-everywhere.patch new file mode 100644 index 0000000..69ee291 --- /dev/null +++ b/SOURCES/kvm-vmdk-Use-vmdk_find_index_in_cluster-everywhere.patch @@ -0,0 +1,71 @@ +From f7f34dfdb448a0344210f6bfa77b67c637ffea56 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:27 +0100 +Subject: [PATCH 14/18] vmdk: Use vmdk_find_index_in_cluster everywhere + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-15-git-send-email-famz@redhat.com> +Patchwork-id: 69180 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 14/18] vmdk: Use vmdk_find_index_in_cluster everywhere +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +Signed-off-by: Fam Zheng +Reviewed-by: Max Reitz +Signed-off-by: Kevin Wolf +(cherry picked from commit 90df601f06de14f062d2e8dc1bc57f0decf86fd1) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 10c08f3..cb5255c 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -1418,7 +1418,6 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, + BDRVVmdkState *s = bs->opaque; + int ret; + uint64_t n, index_in_cluster; +- uint64_t extent_begin_sector, extent_relative_sector_num; + VmdkExtent *extent = NULL; + uint64_t cluster_offset; + +@@ -1430,9 +1429,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, + ret = get_cluster_offset(bs, extent, NULL, + sector_num << 9, false, &cluster_offset, + 0, 0); +- extent_begin_sector = extent->end_sector - extent->sectors; +- extent_relative_sector_num = sector_num - extent_begin_sector; +- index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; ++ index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num); + n = extent->cluster_sectors - index_in_cluster; + if (n > nb_sectors) { + n = nb_sectors; +@@ -1494,7 +1491,6 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, + VmdkExtent *extent = NULL; + int ret; + int64_t index_in_cluster, n; +- uint64_t extent_begin_sector, extent_relative_sector_num; + uint64_t cluster_offset; + VmdkMetaData m_data; + +@@ -1510,9 +1506,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, + if (!extent) { + return -EIO; + } +- extent_begin_sector = extent->end_sector - extent->sectors; +- extent_relative_sector_num = sector_num - extent_begin_sector; +- index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; ++ index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num); + n = extent->cluster_sectors - index_in_cluster; + if (n > nb_sectors) { + n = nb_sectors; +-- +1.8.3.1 + diff --git a/SOURCES/kvm-vmdk-Widen-before-shifting-32-bit-header-field.patch b/SOURCES/kvm-vmdk-Widen-before-shifting-32-bit-header-field.patch new file mode 100644 index 0000000..3042981 --- /dev/null +++ b/SOURCES/kvm-vmdk-Widen-before-shifting-32-bit-header-field.patch @@ -0,0 +1,47 @@ +From 649835536d4bb1366e01ff5600d3005042dd50d5 Mon Sep 17 00:00:00 2001 +From: Fam Zheng +Date: Mon, 15 Feb 2016 09:28:24 +0100 +Subject: [PATCH 11/18] vmdk: Widen before shifting 32 bit header field + +RH-Author: Fam Zheng +Message-id: <1455528511-9357-12-git-send-email-famz@redhat.com> +Patchwork-id: 69177 +O-Subject: [RHEL-7.3 qemu-kvm PATCH 11/18] vmdk: Widen before shifting 32 bit header field +Bugzilla: 1299250 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Max Reitz +RH-Acked-by: Markus Armbruster + +BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1299250 + +Coverity spotted this. + +The field is 32 bits, but if it's possible to overflow in 32 bit +left shift. + +Signed-off-by: Fam Zheng +Reviewed-by: John Snow +Signed-off-by: Kevin Wolf +(cherry picked from commit 7237aecd7e8fcc3ccf7fded77b6c127b4df5d3ac) +Signed-off-by: Fam Zheng +Signed-off-by: Miroslav Rezanina +--- + block/vmdk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 32b3d4c..3810d75 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -525,7 +525,7 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs, + } + ret = vmdk_add_extent(bs, file, false, + le32_to_cpu(header.disk_sectors), +- le32_to_cpu(header.l1dir_offset) << 9, ++ (int64_t)le32_to_cpu(header.l1dir_offset) << 9, + 0, + le32_to_cpu(header.l1dir_size), + 4096, +-- +1.8.3.1 + diff --git a/SPECS/qemu-kvm.spec b/SPECS/qemu-kvm.spec index 1345496..10713e5 100644 --- a/SPECS/qemu-kvm.spec +++ b/SPECS/qemu-kvm.spec @@ -76,7 +76,7 @@ Obsoletes: %1 < %{obsoletes_version} \ Summary: QEMU is a FAST! processor emulator Name: %{pkgname}%{?pkgsuffix} Version: 1.5.3 -Release: 105%{?dist}.7 +Release: 126%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 10 License: GPLv2+ and LGPLv2+ and BSD @@ -97,6 +97,7 @@ Requires: libseccomp >= 1.0.0 %if 0%{!?build_only_sub:1} Requires: glusterfs-api >= 3.6.0 %endif +Requires: libusbx >= 1.0.19 # OOM killer breaks builds with parallel make on s390(x) %ifarch s390 s390x %define _smp_mflags %{nil} @@ -3161,32 +3162,232 @@ Patch1551: kvm-util-uri-Add-overflow-check-to-rfc3986_parse_port.patch Patch1552: kvm-qemu-iotests-Filter-qemu-io-output-in-025.patch # For bz#1270341 - qemu-kvm build failure race condition in tests/ide-test Patch1553: kvm-qtest-ide-test-disable-flush-test.patch -# For bz#1279389 - ceph.conf properties override qemu's command-line properties -Patch1554: kvm-rbd-make-qemu-s-cache-setting-override-any-ceph-sett.patch -# For bz#1279389 - ceph.conf properties override qemu's command-line properties -Patch1555: kvm-rbd-fix-ceph-settings-precedence.patch -# For bz#1298828 - [abrt] qemu-img: get_block_status(): qemu-img killed by SIGABRT -Patch1556: kvm-raw-posix-Fix-.bdrv_co_get_block_status-for-unaligne.patch -# For bz#1298047 - CVE-2016-1714 qemu-kvm: Qemu: nvram: OOB r/w access in processing firmware configurations [rhel-7.2.z] -Patch1557: kvm-fw_cfg-add-check-to-validate-current-entry-value-CVE.patch -# For bz#1331412 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.2.z] -Patch1558: kvm-vga-Remove-some-should-be-done-in-BIOS-comments.patch -# For bz#1331412 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.2.z] -Patch1559: kvm-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch -# For bz#1331412 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.2.z] -Patch1560: kvm-vga-add-vbe_enabled-helper.patch -# For bz#1331412 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.2.z] -Patch1561: kvm-vga-factor-out-vga-register-setup.patch -# For bz#1331412 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.2.z] -Patch1562: kvm-vga-update-vga-register-setup-on-vbe-changes.patch -# For bz#1331412 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.2.z] -Patch1563: kvm-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch -# For bz#1347527 - Regression from CVE-2016-3712: windows installer fails to start -Patch1564: kvm-vga-add-sr_vbe-register-set.patch -# For bz#1359728 - EMBARGOED CVE-2016-5403 qemu-kvm: Qemu: virtio: unbounded memory allocation on host via guest leading to DoS [rhel-7.2.z] -Patch1565: kvm-virtio-error-out-if-guest-exceeds-virtqueue-size.patch -# For bz#1358996 - CVE-2016-5126 qemu-kvm: Qemu: block: iscsi: buffer overflow in iscsi_aio_ioctl [rhel-7.2.z] -Patch1566: kvm-block-iscsi-avoid-potential-overflow-of-acb-task-cdb.patch +# For bz#1268879 - Camera stops work after remote-viewer re-connection [qemu-kvm] +Patch1554: kvm-ehci-clear-suspend-bit-on-detach.patch +# For bz#1277248 - ceph.conf properties override qemu's command-line properties +Patch1555: kvm-rbd-make-qemu-s-cache-setting-override-any-ceph-sett.patch +# For bz#1277248 - ceph.conf properties override qemu's command-line properties +Patch1556: kvm-rbd-fix-ceph-settings-precedence.patch +# For bz#1265427 - contents of MSR_TSC_AUX are not migrated +Patch1557: kvm-target-i386-get-put-MSR_TSC_AUX-across-reset-and-mig.patch +# For bz#1252757 - [RHEL-7.2-qmu-kvm] Package is 100% lost when ping from host to Win2012r2 guest with 64000 size +Patch1558: kvm-rtl8139-Fix-receive-buffer-overflow-check.patch +# For bz#1252757 - [RHEL-7.2-qmu-kvm] Package is 100% lost when ping from host to Win2012r2 guest with 64000 size +Patch1559: kvm-rtl8139-Do-not-consume-the-packet-during-overflow-in.patch +# For bz#1283116 - [abrt] qemu-img: get_block_status(): qemu-img killed by SIGABRT +Patch1560: kvm-raw-posix-Fix-.bdrv_co_get_block_status-for-unaligne.patch +# For bz#1269738 - Vlan table display repeat four times in qmp when queues=4 +Patch1561: kvm-net-Make-qmp_query_rx_filter-with-name-argument-more.patch +# For bz#1298048 - CVE-2016-1714 qemu-kvm: Qemu: nvram: OOB r/w access in processing firmware configurations [rhel-7.3] +Patch1562: kvm-fw_cfg-add-check-to-validate-current-entry-value-CVE.patch +# For bz#1296044 - qemu-kvm: insufficient loop termination conditions in start_xmit() and e1000_receive() [rhel-7.3] +Patch1563: kvm-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch +# For bz#1285453 - An NBD client can cause QEMU main loop to block when connecting to built-in NBD server +Patch1564: kvm-nbd-Always-call-close_fn-in-nbd_client_new.patch +# For bz#1285453 - An NBD client can cause QEMU main loop to block when connecting to built-in NBD server +Patch1565: kvm-nbd-server-Coroutine-based-negotiation.patch +# For bz#1285453 - An NBD client can cause QEMU main loop to block when connecting to built-in NBD server +Patch1566: kvm-nbd-client_close-on-error-in-nbd_co_client_start.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1567: kvm-qemu-io-Remove-unused-args_command.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1568: kvm-cutils-Support-P-and-E-suffixes-in-strtosz.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1569: kvm-qemu-io-Make-cvtnum-a-wrapper-around-strtosz_suffix.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1570: kvm-qemu-io-Handle-cvtnum-errors-in-alloc.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1571: kvm-qemu-io-Don-t-use-global-bs-in-command-implementatio.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1572: kvm-qemu-io-Split-off-commands-to-qemu-io-cmds.c.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1573: kvm-qemu-io-Factor-out-qemuio_command.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1574: kvm-qemu-io-Move-help-function.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1575: kvm-qemu-io-Move-quit-function.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1576: kvm-qemu-io-Move-qemu_strsep-to-cutils.c.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1577: kvm-qemu-io-Move-functions-for-registering-and-running-c.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1578: kvm-qemu-io-Move-command_loop-and-friends.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1579: kvm-qemu-io-Move-remaining-helpers-from-cmd.c.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1580: kvm-qemu-io-Interface-cleanup.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1581: kvm-qemu-io-Use-the-qemu-version-for-V.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1582: kvm-Make-qemu-io-commands-available-in-HMP.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1583: kvm-blkdebug-Add-BLKDBG_FLUSH_TO_OS-DISK-events.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1584: kvm-qemu-io-fix-cvtnum-lval-types.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1585: kvm-qemu-io-Check-for-trailing-chars.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1586: kvm-qemu-io-Correct-error-messages.patch +# For bz#1272523 - qemu-kvm build failure race condition in tests/ide-test +Patch1587: kvm-ide-test-fix-failure-for-test_flush.patch +# For bz#1331413 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.3] +Patch1588: kvm-vga-Remove-some-should-be-done-in-BIOS-comments.patch +# For bz#1331413 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.3] +Patch1589: kvm-vga-fix-banked-access-bounds-checking-CVE-2016-xxxx.patch +# For bz#1331413 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.3] +Patch1590: kvm-vga-add-vbe_enabled-helper.patch +# For bz#1331413 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.3] +Patch1591: kvm-vga-factor-out-vga-register-setup.patch +# For bz#1331413 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.3] +Patch1592: kvm-vga-update-vga-register-setup-on-vbe-changes.patch +# For bz#1331413 - EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.3] +Patch1593: kvm-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1594: kvm-vmdk-Leave-bdi-intact-if-ENOTSUP-in-vmdk_get_info.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1595: kvm-vmdk-Use-g_random_int-to-generate-CID.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1596: kvm-vmdk-Fix-comment-to-match-code-of-extent-lines.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1597: kvm-vmdk-Clean-up-descriptor-file-reading.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1598: kvm-vmdk-Check-descriptor-file-length-when-reading-it.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1599: kvm-vmdk-Remove-unnecessary-initialization.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1600: kvm-vmdk-Set-errp-on-failures-in-vmdk_open_vmdk4.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1601: kvm-block-vmdk-make-ret-variable-usage-clear.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1602: kvm-block-vmdk-move-string-allocations-from-stack-to-the.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1603: kvm-block-vmdk-fixed-sizeof-error.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1604: kvm-vmdk-Widen-before-shifting-32-bit-header-field.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1605: kvm-vmdk-Fix-next_cluster_sector-for-compressed-write.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1606: kvm-vmdk-Fix-index_in_cluster-calculation-in-vmdk_co_get.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1607: kvm-vmdk-Use-vmdk_find_index_in_cluster-everywhere.patch +# For bz#1299250 - qemu-img created VMDK images are unbootable +Patch1608: kvm-vmdk-Fix-next_cluster_sector-for-compressed-write2.patch +# For bz#1299116 - qemu-img created VMDK images lead to "Not a supported disk format (sparse VMDK version too old)" +Patch1609: kvm-vmdk-Create-streamOptimized-as-version-3.patch +# For bz#1299116 - qemu-img created VMDK images lead to "Not a supported disk format (sparse VMDK version too old)" +Patch1610: kvm-vmdk-Fix-converting-to-streamOptimized.patch +# For bz#1299116 - qemu-img created VMDK images lead to "Not a supported disk format (sparse VMDK version too old)" +Patch1611: kvm-vmdk-Fix-calculation-of-block-status-s-offset.patch +# For bz#1312289 - "qemu-kvm: /builddir/build/BUILD/qemu-1.5.3/hw/scsi/virtio-scsi.c:533: virtio_scsi_push_event: Assertion `event == 0' failed" after hotplug 20 virtio-scsi disks then hotunplug them +Patch1612: kvm-virtio-scsi-Prevent-assertion-on-missed-events.patch +# For bz#1177318 - Guest using rbd based image as disk failed to start when sandbox was enabled +Patch1613: kvm-seccomp-adding-sysinfo-system-call-to-whitelist.patch +# For bz#1330969 - match the OEM ID and OEM Table ID fields of the FADT and the RSDT to those of the SLIC +Patch1614: kvm-acpi-strip-compiler-info-in-built-in-DSDT.patch +# For bz#1330969 - match the OEM ID and OEM Table ID fields of the FADT and the RSDT to those of the SLIC +Patch1615: kvm-acpi-fix-endian-ness-for-table-ids.patch +# For bz#1330969 - match the OEM ID and OEM Table ID fields of the FADT and the RSDT to those of the SLIC +Patch1616: kvm-acpi-support-specified-oem-table-id-for-build_header.patch +# For bz#1330969 - match the OEM ID and OEM Table ID fields of the FADT and the RSDT to those of the SLIC +Patch1617: kvm-acpi-take-oem_id-in-build_header-optionally.patch +# For bz#1330969 - match the OEM ID and OEM Table ID fields of the FADT and the RSDT to those of the SLIC +Patch1618: kvm-acpi-expose-oem_id-and-oem_table_id-in-build_rsdt.patch +# For bz#1330969 - match the OEM ID and OEM Table ID fields of the FADT and the RSDT to those of the SLIC +Patch1619: kvm-acpi-add-function-to-extract-oem_id-and-oem_table_id.patch +# For bz#1330969 - match the OEM ID and OEM Table ID fields of the FADT and the RSDT to those of the SLIC +Patch1620: kvm-pc-set-the-OEM-fields-in-the-RSDT-and-the-FADT-from-.patch +# For bz#1156635 - Libvirt is confused that qemu-kvm exposes 'block-job-cancel' but not 'block-stream' +Patch1621: kvm-block-jobs-qemu-kvm-rhel-differentiation.patch +# For bz#1283198 - RFE: backport max monitor limitation from Qemu upstream +Patch1622: kvm-qxl-allow-to-specify-head-limit-to-qxl-driver.patch +# For bz#1283198 - RFE: backport max monitor limitation from Qemu upstream +Patch1623: kvm-qxl-Fix-new-function-name-for-spice-server-library.patch +# For bz#1268345 - posix_fallocate emulation on NFS fails with Bad file descriptor if fd is opened O_WRONLY +Patch1624: kvm-block-raw-posix-Open-file-descriptor-O_RDWR-to-work-.patch +# For bz#1256741 - "CapsLock" will work as "\" when boot a guest with usb-kbd +Patch1625: kvm-hw-input-hid.c-Fix-capslock-hid-code.patch +# For bz#1340971 - qemu: accel=tcg does not implement SSE 4 properly +Patch1626: kvm-target-i386-fix-pcmpxstrx-equal-ordered-strstr-mode.patch +# For bz#1336491 - Ship FD connection patches qemu-kvm part +Patch1627: kvm-spice-do-not-require-TCP-ports.patch +# For bz#1346982 - Regression from CVE-2016-3712: windows installer fails to start +Patch1628: kvm-vga-add-sr_vbe-register-set.patch +# For bz#1340929 - CVE-2016-5126 qemu-kvm: Qemu: block: iscsi: buffer overflow in iscsi_aio_ioctl [rhel-7.3] +Patch1629: kvm-block-iscsi-avoid-potential-overflow-of-acb-task-cdb.patch +# For bz#1327599 - Add Skylake CPU model +Patch1630: kvm-target-i386-add-feature-flags-for-CPUID-EAX-0xd-ECX-.patch +# For bz#1327599 - Add Skylake CPU model +Patch1631: kvm-target-i386-add-Skylake-Client-cpu-model.patch +# For bz#1318199 - expose host BLKSECTGET limit in scsi-block (qemu-kvm) +Patch1632: kvm-util-introduce-MIN_NON_ZERO.patch +# For bz#1318199 - expose host BLKSECTGET limit in scsi-block (qemu-kvm) +Patch1633: kvm-BlockLimits-introduce-max_transfer_length.patch +# For bz#1318199 - expose host BLKSECTGET limit in scsi-block (qemu-kvm) +Patch1634: kvm-block-backend-expose-bs-bl.max_transfer_length.patch +# For bz#1318199 - expose host BLKSECTGET limit in scsi-block (qemu-kvm) +Patch1635: kvm-scsi-generic-Merge-block-max-xfer-len-in-INQUIRY-res.patch +# For bz#1318199 - expose host BLKSECTGET limit in scsi-block (qemu-kvm) +Patch1636: kvm-raw-posix-Fetch-max-sectors-for-host-block-device.patch +# For bz#1318199 - expose host BLKSECTGET limit in scsi-block (qemu-kvm) +Patch1637: kvm-scsi-Advertise-limits-by-blocksize-not-512.patch +# For bz#1318199 - expose host BLKSECTGET limit in scsi-block (qemu-kvm) +Patch1638: kvm-util-Fix-MIN_NON_ZERO.patch +# For bz#1355730 - spice-gtk shows outdated screen state after migration [qemu-kvm] +Patch1639: kvm-qxl-factor-out-qxl_get_check_slot_offset.patch +# For bz#1355730 - spice-gtk shows outdated screen state after migration [qemu-kvm] +Patch1640: kvm-qxl-store-memory-region-and-offset-instead-of-pointe.patch +# For bz#1355730 - spice-gtk shows outdated screen state after migration [qemu-kvm] +Patch1641: kvm-qxl-fix-surface-migration.patch +# For bz#1355730 - spice-gtk shows outdated screen state after migration [qemu-kvm] +Patch1642: kvm-qxl-fix-qxl_set_dirty-call-in-qxl_dirty_one_surface.patch +# For bz#1359729 - CVE-2016-5403 qemu-kvm: Qemu: virtio: unbounded memory allocation on host via guest leading to DoS [rhel-7.3] +Patch1643: kvm-virtio-error-out-if-guest-exceeds-virtqueue-size.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1644: kvm-json-parser-drop-superfluous-assignment-for-token-va.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1645: kvm-qjson-Apply-nesting-limit-more-sanely.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1646: kvm-qjson-Don-t-crash-when-input-exceeds-nesting-limit.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1647: kvm-check-qjson-Add-test-for-JSON-nesting-depth-limit.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1648: kvm-qjson-Spell-out-some-silent-assumptions.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1649: kvm-qjson-Give-each-of-the-six-structural-chars-its-own-.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1650: kvm-qjson-Inline-token_is_keyword-and-simplify.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1651: kvm-qjson-Inline-token_is_escape-and-simplify.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1652: kvm-qjson-replace-QString-in-JSONLexer-with-GString.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1653: kvm-qjson-Convert-to-parser-to-recursive-descent.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1654: kvm-qjson-store-tokens-in-a-GQueue.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1655: kvm-qjson-surprise-allocating-6-QObjects-per-token-is-ex.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1656: kvm-qjson-Limit-number-of-tokens-in-addition-to-total-si.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1657: kvm-json-streamer-Don-t-leak-tokens-on-incomplete-parse.patch +# For bz#1276036 - Crash on QMP input exceeding limits +Patch1658: kvm-json-streamer-fix-double-free-on-exiting-during-a-pa.patch +# For bz#1360137 - GLib-WARNING **: gmem.c:482: custom memory allocation vtable not supported +Patch1659: kvm-trace-remove-malloc-tracing.patch +# For bz#1367040 - QEMU crash when guest notifies non-existent virtqueue +Patch1660: kvm-virtio-validate-the-existence-of-handle_output-befor.patch +# For bz#1371619 - Flags xsaveopt xsavec xgetbv1 are missing on qemu-kvm +Patch1661: kvm-Fix-backport-of-target-i386-add-feature-flags-for-CP.patch +# For bz#1373088 - [FJ7.3 Bug]: virsh dump with both --memory-only and --format option fails +Patch1662: kvm-Add-skip_dump-flag-to-ignore-memory-region-during-du.patch +# For bz#1372459 - [Intel 7.3 Bug] SKL-SP Guest cpu doesn't support avx512 instruction sets(avx512bw, avx512dq and avx512vl) (qemu-kvm) +Patch1663: kvm-target-i386-Add-support-for-FEAT_7_0_ECX.patch +# For bz#1372459 - [Intel 7.3 Bug] SKL-SP Guest cpu doesn't support avx512 instruction sets(avx512bw, avx512dq and avx512vl) (qemu-kvm) +Patch1664: kvm-target-i386-Add-more-Intel-AVX-512-instructions-supp.patch +# For bz#1285453 - An NBD client can cause QEMU main loop to block when connecting to built-in NBD server +Patch1665: kvm-nbd-server-Set-O_NONBLOCK-on-client-fd.patch +# For bz#1376542 - RHSA-2016-1756 breaks migration of instances +Patch1666: kvm-virtio-recalculate-vq-inuse-after-migration.patch BuildRequires: zlib-devel @@ -3366,37 +3567,6 @@ This package contains some diagnostics and debugging tools for KVM, such as kvm_stat. %endif -%package -n libcacard%{?pkgsuffix} -Summary: Common Access Card (CAC) Emulation -Group: Development/Libraries - -%rhel_rhev_conflicts libcacard - -%description -n libcacard%{?pkgsuffix} -Common Access Card (CAC) emulation library. - -%package -n libcacard-tools%{?pkgsuffix} -Summary: CAC Emulation tools -Group: Development/Libraries -Requires: libcacard = %{epoch}:%{version}-%{release} -# older qemu-img has vscclient which is now in libcacard-tools -Requires: qemu-img >= 3:1.3.0-5 - -%rhel_rhev_conflicts libcacard-tools - -%description -n libcacard-tools%{?pkgsuffix} -CAC emulation tools. - -%package -n libcacard-devel%{?pkgsuffix} -Summary: CAC Emulation devel -Group: Development/Libraries -Requires: libcacard = %{epoch}:%{version}-%{release} - -%rhel_rhev_conflicts libcacard-devel - -%description -n libcacard-devel%{?pkgsuffix} -CAC emulation development files. - %prep %setup -q -n qemu-%{version} cp %{SOURCE18} pc-bios # keep "make check" happy @@ -4966,6 +5136,106 @@ cp %{SOURCE18} pc-bios # keep "make check" happy %patch1564 -p1 %patch1565 -p1 %patch1566 -p1 +%patch1567 -p1 +%patch1568 -p1 +%patch1569 -p1 +%patch1570 -p1 +%patch1571 -p1 +%patch1572 -p1 +%patch1573 -p1 +%patch1574 -p1 +%patch1575 -p1 +%patch1576 -p1 +%patch1577 -p1 +%patch1578 -p1 +%patch1579 -p1 +%patch1580 -p1 +%patch1581 -p1 +%patch1582 -p1 +%patch1583 -p1 +%patch1584 -p1 +%patch1585 -p1 +%patch1586 -p1 +%patch1587 -p1 +%patch1588 -p1 +%patch1589 -p1 +%patch1590 -p1 +%patch1591 -p1 +%patch1592 -p1 +%patch1593 -p1 +%patch1594 -p1 +%patch1595 -p1 +%patch1596 -p1 +%patch1597 -p1 +%patch1598 -p1 +%patch1599 -p1 +%patch1600 -p1 +%patch1601 -p1 +%patch1602 -p1 +%patch1603 -p1 +%patch1604 -p1 +%patch1605 -p1 +%patch1606 -p1 +%patch1607 -p1 +%patch1608 -p1 +%patch1609 -p1 +%patch1610 -p1 +%patch1611 -p1 +%patch1612 -p1 +%patch1613 -p1 +%patch1614 -p1 +%patch1615 -p1 +%patch1616 -p1 +%patch1617 -p1 +%patch1618 -p1 +%patch1619 -p1 +%patch1620 -p1 +%patch1621 -p1 +%patch1622 -p1 +%patch1623 -p1 +%patch1624 -p1 +%patch1625 -p1 +%patch1626 -p1 +%patch1627 -p1 +%patch1628 -p1 +%patch1629 -p1 +%patch1630 -p1 +%patch1631 -p1 +%patch1632 -p1 +%patch1633 -p1 +%patch1634 -p1 +%patch1635 -p1 +%patch1636 -p1 +%patch1637 -p1 +%patch1638 -p1 +%patch1639 -p1 +%patch1640 -p1 +%patch1641 -p1 +%patch1642 -p1 +%patch1643 -p1 +%patch1644 -p1 +%patch1645 -p1 +%patch1646 -p1 +%patch1647 -p1 +%patch1648 -p1 +%patch1649 -p1 +%patch1650 -p1 +%patch1651 -p1 +%patch1652 -p1 +%patch1653 -p1 +%patch1654 -p1 +%patch1655 -p1 +%patch1656 -p1 +%patch1657 -p1 +%patch1658 -p1 +%patch1659 -p1 +%patch1660 -p1 +%patch1661 -p1 +%patch1662 -p1 +%patch1663 -p1 +%patch1664 -p1 +%patch1665 -p1 +%patch1666 -p1 %build buildarch="%{kvm_target}-softmmu" @@ -5065,8 +5335,6 @@ dobuild() { --disable-guest-agent \ "$@" - make libcacard.la %{?_smp_mflags} $buildldflags - make vscclient %{?_smp_mflags} $buildldflags make qemu-img %{?_smp_mflags} $buildldflags make qemu-io %{?_smp_mflags} $buildldflags make qemu-nbd %{?_smp_mflags} $buildldflags @@ -5215,6 +5483,12 @@ dobuild --target-list="$buildarch" rom_link ../sgabios/sgabios.bin sgabios.bin %endif +# Remove libcacard +rm -rf $RPM_BUILD_ROOT%{_bindir}/vscclient +rm -rf $RPM_BUILD_ROOT%{_includedir}/cacard +rm -rf $RPM_BUILD_ROOT%{_libdir}/libcacard.so* +rm -rf $RPM_BUILD_ROOT%{_libdir}/pkgconfig/libcacard.pc + %if %{with guest_agent} # For the qemu-guest-agent subpackage, install: # - the systemd service file and the udev rules: @@ -5250,8 +5524,6 @@ dobuild --target-list="$buildarch" install -m 0644 %{SOURCE12} $RPM_BUILD_ROOT%{_sysconfdir}/%{pkgname} %endif -make %{?_smp_mflags} $buildldflags DESTDIR=$RPM_BUILD_ROOT install-libcacard -find $RPM_BUILD_ROOT -name "libcacard.so*" -exec chmod +x \{\} \; find $RPM_BUILD_ROOT -name '*.la' -or -name '*.a' | xargs rm -f @@ -5259,7 +5531,6 @@ find $RPM_BUILD_ROOT -name '*.la' -or -name '*.a' | xargs rm -f mkdir -p $RPM_BUILD_ROOT%{_bindir} mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1/* mkdir -p $RPM_BUILD_ROOT%{_mandir}/man8/* - libtool --mode=install install -m 0755 vscclient $RPM_BUILD_ROOT%{_bindir}/vscclient install -m 0755 qemu-img $RPM_BUILD_ROOT%{_bindir}/qemu-img install -m 0755 qemu-io $RPM_BUILD_ROOT%{_bindir}/qemu-io install -m 0755 qemu-nbd $RPM_BUILD_ROOT%{_bindir}/qemu-nbd @@ -5280,6 +5551,7 @@ find $RPM_BUILD_ROOT -name '*.la' -or -name '*.a' | xargs rm -f %post # load kvm modules now, so we can make sure no reboot is needed. # If there's already a kvm module installed, we don't mess with it +%udev_rules_update sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : udevadm trigger --subsystem-match=misc --sysname-match=kvm --action=add || : @@ -5407,60 +5679,241 @@ sh %{_sysconfdir}/sysconfig/modules/kvm.modules &> /dev/null || : %{_mandir}/man1/qemu-img.1* %{_mandir}/man8/qemu-nbd.8* -%files -n libcacard%{?pkgsuffix} -%defattr(-,root,root,-) -%{_libdir}/libcacard.so.* - -%files -n libcacard-tools%{?pkgsuffix} -%defattr(-,root,root,-) -%{_bindir}/vscclient - -%files -n libcacard-devel%{?pkgsuffix} -%defattr(-,root,root,-) -%{_includedir}/cacard -%{_libdir}/libcacard.so -%{_libdir}/pkgconfig/libcacard.pc - %changelog -* Tue Aug 02 2016 Miroslav Rezanina - 1.5.3-105.el7_2.7 -- kvm-block-iscsi-avoid-potential-overflow-of-acb-task-cdb.patch [bz#1358996] -- Resolves: bz#1358996 - (CVE-2016-5126 qemu-kvm: Qemu: block: iscsi: buffer overflow in iscsi_aio_ioctl [rhel-7.2.z]) - -* Wed Jul 27 2016 Miroslav Rezanina - 1.5.3-105.el7_2.6 -- kvm-virtio-error-out-if-guest-exceeds-virtqueue-size.patch [bz#1359728] -- Resolves: bz#1359728 - (EMBARGOED CVE-2016-5403 qemu-kvm: Qemu: virtio: unbounded memory allocation on host via guest leading to DoS [rhel-7.2.z]) - -* Fri Jul 01 2016 Miroslav Rezanina - 1.5.3-105.el7_2.5 -- kvm-vga-add-sr_vbe-register-set.patch [bz#1347527] -- Resolves: bz#1347527 +* Tue Sep 20 2016 Miroslav Rezanina - 1.5.3-126.el7 +- kvm-virtio-recalculate-vq-inuse-after-migration.patch [bz#1376542] +- Resolves: bz#1376542 + (RHSA-2016-1756 breaks migration of instances) + +* Thu Sep 15 2016 Miroslav Rezanina - 1.5.3-125.el7 +- kvm-nbd-server-Set-O_NONBLOCK-on-client-fd.patch [bz#1285453] +- Resolves: bz#1285453 + (An NBD client can cause QEMU main loop to block when connecting to built-in NBD server) + +* Tue Sep 13 2016 Miroslav Rezanina - 1.5.3-124.el7 +- kvm-target-i386-Add-support-for-FEAT_7_0_ECX.patch [bz#1372459] +- kvm-target-i386-Add-more-Intel-AVX-512-instructions-supp.patch [bz#1372459] +- Resolves: bz#1372459 + ([Intel 7.3 Bug] SKL-SP Guest cpu doesn't support avx512 instruction sets(avx512bw, avx512dq and avx512vl) (qemu-kvm)) + +* Fri Sep 09 2016 Miroslav Rezanina - 1.5.3-123.el7 +- kvm-Fix-backport-of-target-i386-add-feature-flags-for-CP.patch [bz#1371619] +- kvm-Add-skip_dump-flag-to-ignore-memory-region-during-du.patch [bz#1373088] +- Resolves: bz#1371619 + (Flags xsaveopt xsavec xgetbv1 are missing on qemu-kvm) +- Resolves: bz#1373088 + ([FJ7.3 Bug]: virsh dump with both --memory-only and --format option fails) + +* Fri Aug 26 2016 Miroslav Rezanina - 1.5.3-122.el7 +- kvm-virtio-validate-the-existence-of-handle_output-befor.patch [bz#1367040] +- Resolves: bz#1367040 + (QEMU crash when guest notifies non-existent virtqueue) + +* Tue Aug 02 2016 Miroslav Rezanina - 1.5.3-121.el7 +- kvm-json-parser-drop-superfluous-assignment-for-token-va.patch [bz#1276036] +- kvm-qjson-Apply-nesting-limit-more-sanely.patch [bz#1276036] +- kvm-qjson-Don-t-crash-when-input-exceeds-nesting-limit.patch [bz#1276036] +- kvm-check-qjson-Add-test-for-JSON-nesting-depth-limit.patch [bz#1276036] +- kvm-qjson-Spell-out-some-silent-assumptions.patch [bz#1276036] +- kvm-qjson-Give-each-of-the-six-structural-chars-its-own-.patch [bz#1276036] +- kvm-qjson-Inline-token_is_keyword-and-simplify.patch [bz#1276036] +- kvm-qjson-Inline-token_is_escape-and-simplify.patch [bz#1276036] +- kvm-qjson-replace-QString-in-JSONLexer-with-GString.patch [bz#1276036] +- kvm-qjson-Convert-to-parser-to-recursive-descent.patch [bz#1276036] +- kvm-qjson-store-tokens-in-a-GQueue.patch [bz#1276036] +- kvm-qjson-surprise-allocating-6-QObjects-per-token-is-ex.patch [bz#1276036] +- kvm-qjson-Limit-number-of-tokens-in-addition-to-total-si.patch [bz#1276036] +- kvm-json-streamer-Don-t-leak-tokens-on-incomplete-parse.patch [bz#1276036] +- kvm-json-streamer-fix-double-free-on-exiting-during-a-pa.patch [bz#1276036] +- kvm-trace-remove-malloc-tracing.patch [bz#1360137] +- Resolves: bz#1276036 + (Crash on QMP input exceeding limits) +- Resolves: bz#1360137 + (GLib-WARNING **: gmem.c:482: custom memory allocation vtable not supported) + +* Fri Jul 29 2016 Miroslav Rezanina - 1.5.3-120.el7 +- kvm-Add-install-dependency-to-newer-libusbx-version.patch [bz#1351106] +- kvm-virtio-error-out-if-guest-exceeds-virtqueue-size.patch [bz#1359729] +- Resolves: bz#1351106 + (symbol lookup error: /usr/libexec/qemu-kvm: undefined symbol: libusb_get_port_numbers) +- Resolves: bz#1359729 + (CVE-2016-5403 qemu-kvm: Qemu: virtio: unbounded memory allocation on host via guest leading to DoS [rhel-7.3]) + +* Tue Jul 26 2016 Miroslav Rezanina - 1.5.3-119.el7 +- kvm-qxl-factor-out-qxl_get_check_slot_offset.patch [bz#1355730] +- kvm-qxl-store-memory-region-and-offset-instead-of-pointe.patch [bz#1355730] +- kvm-qxl-fix-surface-migration.patch [bz#1355730] +- kvm-qxl-fix-qxl_set_dirty-call-in-qxl_dirty_one_surface.patch [bz#1355730] +- Resolves: bz#1355730 + (spice-gtk shows outdated screen state after migration [qemu-kvm]) + +* Tue Jul 19 2016 Miroslav Rezanina - 1.5.3-118.el7 +- kvm-util-introduce-MIN_NON_ZERO.patch [bz#1318199] +- kvm-BlockLimits-introduce-max_transfer_length.patch [bz#1318199] +- kvm-block-backend-expose-bs-bl.max_transfer_length.patch [bz#1318199] +- kvm-scsi-generic-Merge-block-max-xfer-len-in-INQUIRY-res.patch [bz#1318199] +- kvm-raw-posix-Fetch-max-sectors-for-host-block-device.patch [bz#1318199] +- kvm-scsi-Advertise-limits-by-blocksize-not-512.patch [bz#1318199] +- kvm-util-Fix-MIN_NON_ZERO.patch [bz#1318199] +- Resolves: bz#1318199 + (expose host BLKSECTGET limit in scsi-block (qemu-kvm)) + +* Tue Jul 12 2016 Miroslav Rezanina - 1.5.3-117.el7 +- kvm-target-i386-add-feature-flags-for-CPUID-EAX-0xd-ECX-.patch [bz#1327599] +- kvm-target-i386-add-Skylake-Client-cpu-model.patch [bz#1327599] +- Resolves: bz#1327599 + (Add Skylake CPU model) + +* Tue Jun 28 2016 Miroslav Rezanina - 1.5.3-116.el7 +- kvm-block-iscsi-avoid-potential-overflow-of-acb-task-cdb.patch [bz#1340929] +- Resolves: bz#1340929 + (CVE-2016-5126 qemu-kvm: Qemu: block: iscsi: buffer overflow in iscsi_aio_ioctl [rhel-7.3]) + +* Mon Jun 20 2016 Miroslav Rezanina - 1.5.3-115.el7 +- kvm-spice-do-not-require-TCP-ports.patch [bz#1336491] +- kvm-vga-add-sr_vbe-register-set.patch [bz#1346982] +- Resolves: bz#1336491 + (Ship FD connection patches qemu-kvm part) +- Resolves: bz#1346982 (Regression from CVE-2016-3712: windows installer fails to start) -* Tue May 03 2016 Miroslav Rezanina - 1.5.3-105.el7_2.4 -- kvm-vga-Remove-some-should-be-done-in-BIOS-comments.patch [bz#1331412] -- kvm-vga-fix-banked-access-bounds-checking-CVE-2016-3710.patch [bz#1331412] -- kvm-vga-add-vbe_enabled-helper.patch [bz#1331412] -- kvm-vga-factor-out-vga-register-setup.patch [bz#1331412] -- kvm-vga-update-vga-register-setup-on-vbe-changes.patch [bz#1331412] -- kvm-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch [bz#1331412] -- Resolves: bz#1331412 - (EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.2.z]) - -* Thu Jan 21 2016 Miroslav Rezanina - 1.5.3-105.el7_2.3 -- kvm-fw_cfg-add-check-to-validate-current-entry-value-CVE.patch [bz#1298047] -- Resolves: bz#1298047 - (CVE-2016-1714 qemu-kvm: Qemu: nvram: OOB r/w access in processing firmware configurations [rhel-7.2.z]) - -* Wed Jan 20 2016 Miroslav Rezanina - 1.5.3-105.el7_2.2 -- kvm-raw-posix-Fix-.bdrv_co_get_block_status-for-unaligne.patch [bz#1298828] -- Resolves: bz#1298828 +* Wed Jun 15 2016 Miroslav Rezanina - 1.5.3-114.el7 +- kvm-hw-input-hid.c-Fix-capslock-hid-code.patch [bz#1256741] +- kvm-target-i386-fix-pcmpxstrx-equal-ordered-strstr-mode.patch [bz#1340971] +- kvm-spec-Update-rules-before-triggering-for-kvm-device.patch [bz#1333159] +- Resolves: bz#1256741 + ("CapsLock" will work as "\" when boot a guest with usb-kbd) +- Resolves: bz#1333159 + (qemu-kvm doesn't reload udev rules before triggering for kvm device) +- Resolves: bz#1340971 + (qemu: accel=tcg does not implement SSE 4 properly) + +* Sat May 28 2016 Jeff E. Nelson - 1.5.3-113.el7 +- kvm-qxl-allow-to-specify-head-limit-to-qxl-driver.patch [bz#1283198] +- kvm-qxl-Fix-new-function-name-for-spice-server-library.patch [bz#1283198] +- kvm-block-raw-posix-Open-file-descriptor-O_RDWR-to-work-.patch [bz#1268345] +- Resolves: bz#1268345 + (posix_fallocate emulation on NFS fails with Bad file descriptor if fd is opened O_WRONLY) +- Resolves: bz#1283198 + (RFE: backport max monitor limitation from Qemu upstream) + +* Mon May 16 2016 Miroslav Rezanina - 1.5.3-112.el7 +- kvm-virtio-scsi-Prevent-assertion-on-missed-events.patch [bz#1312289] +- kvm-seccomp-adding-sysinfo-system-call-to-whitelist.patch [bz#1177318] +- kvm-acpi-strip-compiler-info-in-built-in-DSDT.patch [bz#1330969] +- kvm-acpi-fix-endian-ness-for-table-ids.patch [bz#1330969] +- kvm-acpi-support-specified-oem-table-id-for-build_header.patch [bz#1330969] +- kvm-acpi-take-oem_id-in-build_header-optionally.patch [bz#1330969] +- kvm-acpi-expose-oem_id-and-oem_table_id-in-build_rsdt.patch [bz#1330969] +- kvm-acpi-add-function-to-extract-oem_id-and-oem_table_id.patch [bz#1330969] +- kvm-pc-set-the-OEM-fields-in-the-RSDT-and-the-FADT-from-.patch [bz#1330969] +- kvm-block-jobs-qemu-kvm-rhel-differentiation.patch [bz#1156635] +- Resolves: bz#1156635 + (Libvirt is confused that qemu-kvm exposes 'block-job-cancel' but not 'block-stream') +- Resolves: bz#1177318 + (Guest using rbd based image as disk failed to start when sandbox was enabled) +- Resolves: bz#1312289 + ("qemu-kvm: /builddir/build/BUILD/qemu-1.5.3/hw/scsi/virtio-scsi.c:533: virtio_scsi_push_event: Assertion `event == 0' failed" after hotplug 20 virtio-scsi disks then hotunplug them) +- Resolves: bz#1330969 + (match the OEM ID and OEM Table ID fields of the FADT and the RSDT to those of the SLIC) + +* Thu May 05 2016 Miroslav Rezanina - 1.5.3-111.el7 +- kvm-vmdk-Leave-bdi-intact-if-ENOTSUP-in-vmdk_get_info.patch [bz#1299250] +- kvm-vmdk-Use-g_random_int-to-generate-CID.patch [bz#1299250] +- kvm-vmdk-Fix-comment-to-match-code-of-extent-lines.patch [bz#1299250] +- kvm-vmdk-Clean-up-descriptor-file-reading.patch [bz#1299250] +- kvm-vmdk-Check-descriptor-file-length-when-reading-it.patch [bz#1299250] +- kvm-vmdk-Remove-unnecessary-initialization.patch [bz#1299250] +- kvm-vmdk-Set-errp-on-failures-in-vmdk_open_vmdk4.patch [bz#1299250] +- kvm-block-vmdk-make-ret-variable-usage-clear.patch [bz#1299250] +- kvm-block-vmdk-move-string-allocations-from-stack-to-the.patch [bz#1299250] +- kvm-block-vmdk-fixed-sizeof-error.patch [bz#1299250] +- kvm-vmdk-Widen-before-shifting-32-bit-header-field.patch [bz#1299250] +- kvm-vmdk-Fix-next_cluster_sector-for-compressed-write.patch [bz#1299250] +- kvm-vmdk-Fix-index_in_cluster-calculation-in-vmdk_co_get.patch [bz#1299250] +- kvm-vmdk-Use-vmdk_find_index_in_cluster-everywhere.patch [bz#1299250] +- kvm-vmdk-Fix-next_cluster_sector-for-compressed-write2.patch [bz#1299250] +- kvm-vmdk-Create-streamOptimized-as-version-3.patch [bz#1299116] +- kvm-vmdk-Fix-converting-to-streamOptimized.patch [bz#1299116] +- kvm-vmdk-Fix-calculation-of-block-status-s-offset.patch [bz#1299116] +- Resolves: bz#1299116 + (qemu-img created VMDK images lead to "Not a supported disk format (sparse VMDK version too old)") +- Resolves: bz#1299250 + (qemu-img created VMDK images are unbootable) + +* Wed May 04 2016 Miroslav Rezanina - 1.5.3-110.el7 +- kvm-qemu-io-Remove-unused-args_command.patch [bz#1272523] +- kvm-cutils-Support-P-and-E-suffixes-in-strtosz.patch [bz#1272523] +- kvm-qemu-io-Make-cvtnum-a-wrapper-around-strtosz_suffix.patch [bz#1272523] +- kvm-qemu-io-Handle-cvtnum-errors-in-alloc.patch [bz#1272523] +- kvm-qemu-io-Don-t-use-global-bs-in-command-implementatio.patch [bz#1272523] +- kvm-qemu-io-Split-off-commands-to-qemu-io-cmds.c.patch [bz#1272523] +- kvm-qemu-io-Factor-out-qemuio_command.patch [bz#1272523] +- kvm-qemu-io-Move-help-function.patch [bz#1272523] +- kvm-qemu-io-Move-quit-function.patch [bz#1272523] +- kvm-qemu-io-Move-qemu_strsep-to-cutils.c.patch [bz#1272523] +- kvm-qemu-io-Move-functions-for-registering-and-running-c.patch [bz#1272523] +- kvm-qemu-io-Move-command_loop-and-friends.patch [bz#1272523] +- kvm-qemu-io-Move-remaining-helpers-from-cmd.c.patch [bz#1272523] +- kvm-qemu-io-Interface-cleanup.patch [bz#1272523] +- kvm-qemu-io-Use-the-qemu-version-for-V.patch [bz#1272523] +- kvm-Make-qemu-io-commands-available-in-HMP.patch [bz#1272523] +- kvm-blkdebug-Add-BLKDBG_FLUSH_TO_OS-DISK-events.patch [bz#1272523] +- kvm-qemu-io-fix-cvtnum-lval-types.patch [bz#1272523] +- kvm-qemu-io-Check-for-trailing-chars.patch [bz#1272523] +- kvm-qemu-io-Correct-error-messages.patch [bz#1272523] +- kvm-ide-test-fix-failure-for-test_flush.patch [bz#1272523] +- kvm-vga-Remove-some-should-be-done-in-BIOS-comments.patch [bz#1331413] +- kvm-vga-fix-banked-access-bounds-checking-CVE-2016-xxxx.patch [bz#1331413] +- kvm-vga-add-vbe_enabled-helper.patch [bz#1331413] +- kvm-vga-factor-out-vga-register-setup.patch [bz#1331413] +- kvm-vga-update-vga-register-setup-on-vbe-changes.patch [bz#1331413] +- kvm-vga-make-sure-vga-register-setup-for-vbe-stays-intac.patch [bz#1331413] +- Resolves: bz#1272523 + (qemu-kvm build failure race condition in tests/ide-test) +- Resolves: bz#1331413 + (EMBARGOED CVE-2016-3710 qemu-kvm: qemu: incorrect banked access bounds checking in vga module [rhel-7.3]) + +* Mon Mar 14 2016 Miroslav Rezanina - 1.5.3-109.el7 +- kvm-e1000-eliminate-infinite-loops-on-out-of-bounds-tran.patch [bz#1296044] +- kvm-nbd-Always-call-close_fn-in-nbd_client_new.patch [bz#1285453] +- kvm-nbd-server-Coroutine-based-negotiation.patch [bz#1285453] +- kvm-nbd-client_close-on-error-in-nbd_co_client_start.patch [bz#1285453] +- kvm-Remove-libcacard-build.patch [bz#1314153] +- Resolves: bz#1285453 + (An NBD client can cause QEMU main loop to block when connecting to built-in NBD server) +- Resolves: bz#1296044 + (qemu-kvm: insufficient loop termination conditions in start_xmit() and e1000_receive() [rhel-7.3]) +- Resolves: bz#1314153 + (Disable building of libcacard) + +* Mon Feb 08 2016 Miroslav Rezanina - 1.5.3-108.el7 +- kvm-net-Make-qmp_query_rx_filter-with-name-argument-more.patch [bz#1269738] +- kvm-fw_cfg-add-check-to-validate-current-entry-value-CVE.patch [bz#1298048] +- Resolves: bz#1269738 + (Vlan table display repeat four times in qmp when queues=4) +- Resolves: bz#1298048 + (CVE-2016-1714 qemu-kvm: Qemu: nvram: OOB r/w access in processing firmware configurations [rhel-7.3]) + +* Wed Jan 20 2016 Miroslav Rezanina - 1.5.3-107.el7 +- kvm-raw-posix-Fix-.bdrv_co_get_block_status-for-unaligne.patch [bz#1283116] +- Resolves: bz#1283116 ([abrt] qemu-img: get_block_status(): qemu-img killed by SIGABRT) -* Tue Nov 17 2015 Miroslav Rezanina - 1.5.3-105.el7_2.1 -- kvm-rbd-make-qemu-s-cache-setting-override-any-ceph-sett.patch [bz#1279389] -- kvm-rbd-fix-ceph-settings-precedence.patch [bz#1279389] -- Resolves: bz#1279389 +* Wed Jan 13 2016 Miroslav Rezanina - 1.5.3-106.el7 +- kvm-ehci-clear-suspend-bit-on-detach.patch [bz#1268879] +- kvm-rbd-make-qemu-s-cache-setting-override-any-ceph-sett.patch [bz#1277248] +- kvm-rbd-fix-ceph-settings-precedence.patch [bz#1277248] +- kvm-target-i386-get-put-MSR_TSC_AUX-across-reset-and-mig.patch [bz#1265427] +- kvm-rtl8139-Fix-receive-buffer-overflow-check.patch [bz#1252757] +- kvm-rtl8139-Do-not-consume-the-packet-during-overflow-in.patch [bz#1252757] +- Resolves: bz#1252757 + ([RHEL-7.2-qmu-kvm] Package is 100% lost when ping from host to Win2012r2 guest with 64000 size) +- Resolves: bz#1265427 + (contents of MSR_TSC_AUX are not migrated) +- Resolves: bz#1268879 + (Camera stops work after remote-viewer re-connection [qemu-kvm]) +- Resolves: bz#1277248 (ceph.conf properties override qemu's command-line properties) * Fri Oct 16 2015 Jeff E. Nelson - 1.5.3-105.el7