From a6628605f77857c32325e5f591521298137b1686 Mon Sep 17 00:00:00 2001 From: Miroslav Rezanina Date: Thu, 9 Feb 2023 09:45:40 -0500 Subject: [PATCH] * Thu Feb 09 2023 Miroslav Rezanina - 7.2.0-8 - kvm-qcow2-Fix-theoretical-corruption-in-store_bitmap-err.patch [bz#2150180] - kvm-qemu-img-commit-Report-errors-while-closing-the-imag.patch [bz#2150180] - kvm-qemu-img-bitmap-Report-errors-while-closing-the-imag.patch [bz#2150180] - kvm-qemu-iotests-Test-qemu-img-bitmap-commit-exit-code-o.patch [bz#2150180] - kvm-accel-tcg-Test-CPUJumpCache-in-tb_jmp_cache_clear_pa.patch [bz#2165280] - kvm-block-Improve-empty-format-specific-info-dump.patch [bz#1860292] - kvm-block-file-Add-file-specific-image-info.patch [bz#1860292] - kvm-block-vmdk-Change-extent-info-type.patch [bz#1860292] - kvm-block-Split-BlockNodeInfo-off-of-ImageInfo.patch [bz#1860292] - kvm-qemu-img-Use-BlockNodeInfo.patch [bz#1860292] - kvm-block-qapi-Let-bdrv_query_image_info-recurse.patch [bz#1860292] - kvm-block-qapi-Introduce-BlockGraphInfo.patch [bz#1860292] - kvm-block-qapi-Add-indentation-to-bdrv_node_info_dump.patch [bz#1860292] - kvm-iotests-Filter-child-node-information.patch [bz#1860292] - kvm-iotests-106-214-308-Read-only-one-size-line.patch [bz#1860292] - kvm-qemu-img-Let-info-print-block-graph.patch [bz#1860292] - kvm-qemu-img-Change-info-key-names-for-protocol-nodes.patch [bz#1860292] - kvm-Revert-vhost-user-Monitor-slave-channel-in-vhost_use.patch [bz#2155173] - kvm-Revert-vhost-user-Introduce-nested-event-loop-in-vho.patch [bz#2155173] - kvm-virtio-rng-pci-fix-transitional-migration-compat-for.patch [bz#2162569] - Resolves: bz#2150180 (qemu-img finishes successfully while having errors in commit or bitmaps operations) - Resolves: bz#2165280 ([kvm-unit-tests] debug-wp-migration fails) - Resolves: bz#1860292 (RFE: add extent_size_hint information to qemu-img info) - Resolves: bz#2155173 ([vhost-user] unable to start vhost net: 71: falling back on userspace) - Resolves: bz#2162569 ([transitional device][virtio-rng-pci-transitional]Stable Guest ABI failed between RHEL 8.6 to RHEL 9.2) --- ...r-Introduce-nested-event-loop-in-vho.patch | 140 ++++++++++ ...r-Monitor-slave-channel-in-vhost_use.patch | 143 ++++++++++ ...PUJumpCache-in-tb_jmp_cache_clear_pa.patch | 58 ++++ ...rove-empty-format-specific-info-dump.patch | 132 +++++++++ ...Split-BlockNodeInfo-off-of-ImageInfo.patch | 246 +++++++++++++++++ ...ck-file-Add-file-specific-image-info.patch | 145 ++++++++++ ...d-indentation-to-bdrv_node_info_dump.patch | 206 ++++++++++++++ kvm-block-qapi-Introduce-BlockGraphInfo.patch | 155 +++++++++++ ...pi-Let-bdrv_query_image_info-recurse.patch | 197 +++++++++++++ kvm-block-vmdk-Change-extent-info-type.patch | 140 ++++++++++ ...-106-214-308-Read-only-one-size-line.patch | 99 +++++++ ...otests-Filter-child-node-information.patch | 171 ++++++++++++ ...tical-corruption-in-store_bitmap-err.patch | 67 +++++ ...ge-info-key-names-for-protocol-nodes.patch | 197 +++++++++++++ kvm-qemu-img-Let-info-print-block-graph.patch | 261 ++++++++++++++++++ kvm-qemu-img-Use-BlockNodeInfo.patch | 241 ++++++++++++++++ ...Report-errors-while-closing-the-imag.patch | 70 +++++ ...Report-errors-while-closing-the-imag.patch | 67 +++++ ...t-qemu-img-bitmap-commit-exit-code-o.patch | 166 +++++++++++ ...ix-transitional-migration-compat-for.patch | 47 ++++ qemu-kvm.spec | 74 ++++- 21 files changed, 3021 insertions(+), 1 deletion(-) create mode 100644 kvm-Revert-vhost-user-Introduce-nested-event-loop-in-vho.patch create mode 100644 kvm-Revert-vhost-user-Monitor-slave-channel-in-vhost_use.patch create mode 100644 kvm-accel-tcg-Test-CPUJumpCache-in-tb_jmp_cache_clear_pa.patch create mode 100644 kvm-block-Improve-empty-format-specific-info-dump.patch create mode 100644 kvm-block-Split-BlockNodeInfo-off-of-ImageInfo.patch create mode 100644 kvm-block-file-Add-file-specific-image-info.patch create mode 100644 kvm-block-qapi-Add-indentation-to-bdrv_node_info_dump.patch create mode 100644 kvm-block-qapi-Introduce-BlockGraphInfo.patch create mode 100644 kvm-block-qapi-Let-bdrv_query_image_info-recurse.patch create mode 100644 kvm-block-vmdk-Change-extent-info-type.patch create mode 100644 kvm-iotests-106-214-308-Read-only-one-size-line.patch create mode 100644 kvm-iotests-Filter-child-node-information.patch create mode 100644 kvm-qcow2-Fix-theoretical-corruption-in-store_bitmap-err.patch create mode 100644 kvm-qemu-img-Change-info-key-names-for-protocol-nodes.patch create mode 100644 kvm-qemu-img-Let-info-print-block-graph.patch create mode 100644 kvm-qemu-img-Use-BlockNodeInfo.patch create mode 100644 kvm-qemu-img-bitmap-Report-errors-while-closing-the-imag.patch create mode 100644 kvm-qemu-img-commit-Report-errors-while-closing-the-imag.patch create mode 100644 kvm-qemu-iotests-Test-qemu-img-bitmap-commit-exit-code-o.patch create mode 100644 kvm-virtio-rng-pci-fix-transitional-migration-compat-for.patch diff --git a/kvm-Revert-vhost-user-Introduce-nested-event-loop-in-vho.patch b/kvm-Revert-vhost-user-Introduce-nested-event-loop-in-vho.patch new file mode 100644 index 0000000..752aa08 --- /dev/null +++ b/kvm-Revert-vhost-user-Introduce-nested-event-loop-in-vho.patch @@ -0,0 +1,140 @@ +From 0c19fb7c4a22a30830152b224b2e66963f829a7a Mon Sep 17 00:00:00 2001 +From: Greg Kurz +Date: Thu, 19 Jan 2023 18:24:24 +0100 +Subject: [PATCH 19/20] Revert "vhost-user: Introduce nested event loop in + vhost_user_read()" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Laurent Vivier +RH-MergeRequest: 146: Fix vhost-user with dpdk +RH-Bugzilla: 2155173 +RH-Acked-by: Cindy Lu +RH-Acked-by: Greg Kurz (RH) +RH-Acked-by: Eugenio Pérez +RH-Commit: [2/2] 9b67041f92f29f70b7ccb41d8087801e4e4e38af (lvivier/qemu-kvm-centos) + +This reverts commit a7f523c7d114d445c5d83aecdba3efc038e5a692. + +The nested event loop is broken by design. It's only user was removed. +Drop the code as well so that nobody ever tries to use it again. + +I had to fix a couple of trivial conflicts around return values because +of 025faa872bcf ("vhost-user: stick to -errno error return convention"). + +Signed-off-by: Greg Kurz +Message-Id: <20230119172424.478268-3-groug@kaod.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Maxime Coquelin +(cherry picked from commit 4382138f642f69fdbc79ebf4e93d84be8061191f) +Signed-off-by: Laurent Vivier +--- + hw/virtio/vhost-user.c | 65 ++++-------------------------------------- + 1 file changed, 5 insertions(+), 60 deletions(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 0ac00eb901..7cb49c50f9 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -305,19 +305,8 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg) + return 0; + } + +-struct vhost_user_read_cb_data { +- struct vhost_dev *dev; +- VhostUserMsg *msg; +- GMainLoop *loop; +- int ret; +-}; +- +-static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, +- gpointer opaque) ++static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) + { +- struct vhost_user_read_cb_data *data = opaque; +- struct vhost_dev *dev = data->dev; +- VhostUserMsg *msg = data->msg; + struct vhost_user *u = dev->opaque; + CharBackend *chr = u->user->chr; + uint8_t *p = (uint8_t *) msg; +@@ -325,8 +314,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, + + r = vhost_user_read_header(dev, msg); + if (r < 0) { +- data->ret = r; +- goto end; ++ return r; + } + + /* validate message size is sane */ +@@ -334,8 +322,7 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, + error_report("Failed to read msg header." + " Size %d exceeds the maximum %zu.", msg->hdr.size, + VHOST_USER_PAYLOAD_SIZE); +- data->ret = -EPROTO; +- goto end; ++ return -EPROTO; + } + + if (msg->hdr.size) { +@@ -346,53 +333,11 @@ static gboolean vhost_user_read_cb(void *do_not_use, GIOCondition condition, + int saved_errno = errno; + error_report("Failed to read msg payload." + " Read %d instead of %d.", r, msg->hdr.size); +- data->ret = r < 0 ? -saved_errno : -EIO; +- goto end; ++ return r < 0 ? -saved_errno : -EIO; + } + } + +-end: +- g_main_loop_quit(data->loop); +- return G_SOURCE_REMOVE; +-} +- +-static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) +-{ +- struct vhost_user *u = dev->opaque; +- CharBackend *chr = u->user->chr; +- GMainContext *prev_ctxt = chr->chr->gcontext; +- GMainContext *ctxt = g_main_context_new(); +- GMainLoop *loop = g_main_loop_new(ctxt, FALSE); +- struct vhost_user_read_cb_data data = { +- .dev = dev, +- .loop = loop, +- .msg = msg, +- .ret = 0 +- }; +- +- /* +- * We want to be able to monitor the slave channel fd while waiting +- * for chr I/O. This requires an event loop, but we can't nest the +- * one to which chr is currently attached : its fd handlers might not +- * be prepared for re-entrancy. So we create a new one and switch chr +- * to use it. +- */ +- qemu_chr_be_update_read_handlers(chr->chr, ctxt); +- qemu_chr_fe_add_watch(chr, G_IO_IN | G_IO_HUP, vhost_user_read_cb, &data); +- +- g_main_loop_run(loop); +- +- /* +- * Restore the previous event loop context. This also destroys/recreates +- * event sources : this guarantees that all pending events in the original +- * context that have been processed by the nested loop are purged. +- */ +- qemu_chr_be_update_read_handlers(chr->chr, prev_ctxt); +- +- g_main_loop_unref(loop); +- g_main_context_unref(ctxt); +- +- return data.ret; ++ return 0; + } + + static int process_message_reply(struct vhost_dev *dev, +-- +2.31.1 + diff --git a/kvm-Revert-vhost-user-Monitor-slave-channel-in-vhost_use.patch b/kvm-Revert-vhost-user-Monitor-slave-channel-in-vhost_use.patch new file mode 100644 index 0000000..8e7b906 --- /dev/null +++ b/kvm-Revert-vhost-user-Monitor-slave-channel-in-vhost_use.patch @@ -0,0 +1,143 @@ +From 9fb47ad317ad8cdda9960190d499ad6c3a9817f0 Mon Sep 17 00:00:00 2001 +From: Greg Kurz +Date: Thu, 19 Jan 2023 18:24:23 +0100 +Subject: [PATCH 18/20] Revert "vhost-user: Monitor slave channel in + vhost_user_read()" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Laurent Vivier +RH-MergeRequest: 146: Fix vhost-user with dpdk +RH-Bugzilla: 2155173 +RH-Acked-by: Cindy Lu +RH-Acked-by: Greg Kurz (RH) +RH-Acked-by: Eugenio Pérez +RH-Commit: [1/2] c583a7f121ca9c93c9a2ad17bf0ccf5c1241dc99 (lvivier/qemu-kvm-centos) + +This reverts commit db8a3772e300c1a656331a92da0785d81667dc81. + +Motivation : this is breaking vhost-user with DPDK as reported in [0]. + +Received unexpected msg type. Expected 22 received 40 +Fail to update device iotlb +Received unexpected msg type. Expected 40 received 22 +Received unexpected msg type. Expected 22 received 11 +Fail to update device iotlb +Received unexpected msg type. Expected 11 received 22 +vhost VQ 1 ring restore failed: -71: Protocol error (71) +Received unexpected msg type. Expected 22 received 11 +Fail to update device iotlb +Received unexpected msg type. Expected 11 received 22 +vhost VQ 0 ring restore failed: -71: Protocol error (71) +unable to start vhost net: 71: falling back on userspace virtio + +The failing sequence that leads to the first error is : +- QEMU sends a VHOST_USER_GET_STATUS (40) request to DPDK on the master + socket +- QEMU starts a nested event loop in order to wait for the + VHOST_USER_GET_STATUS response and to be able to process messages from + the slave channel +- DPDK sends a couple of legitimate IOTLB miss messages on the slave + channel +- QEMU processes each IOTLB request and sends VHOST_USER_IOTLB_MSG (22) + updates on the master socket +- QEMU assumes to receive a response for the latest VHOST_USER_IOTLB_MSG + but it gets the response for the VHOST_USER_GET_STATUS instead + +The subsequent errors have the same root cause : the nested event loop +breaks the order by design. It lures QEMU to expect responses to the +latest message sent on the master socket to arrive first. + +Since this was only needed for DAX enablement which is still not merged +upstream, just drop the code for now. A working solution will have to +be merged later on. Likely protect the master socket with a mutex +and service the slave channel with a separate thread, as discussed with +Maxime in the mail thread below. + +[0] https://lore.kernel.org/qemu-devel/43145ede-89dc-280e-b953-6a2b436de395@redhat.com/ + +Reported-by: Yanghang Liu +Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2155173 +Signed-off-by: Greg Kurz +Message-Id: <20230119172424.478268-2-groug@kaod.org> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Acked-by: Stefan Hajnoczi +Acked-by: Maxime Coquelin +(cherry picked from commit f340a59d5a852d75ae34555723694c7e8eafbd0c) +Signed-off-by: Laurent Vivier +--- + hw/virtio/vhost-user.c | 35 +++-------------------------------- + 1 file changed, 3 insertions(+), 32 deletions(-) + +diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c +index 8f635844af..0ac00eb901 100644 +--- a/hw/virtio/vhost-user.c ++++ b/hw/virtio/vhost-user.c +@@ -356,35 +356,6 @@ end: + return G_SOURCE_REMOVE; + } + +-static gboolean slave_read(QIOChannel *ioc, GIOCondition condition, +- gpointer opaque); +- +-/* +- * This updates the read handler to use a new event loop context. +- * Event sources are removed from the previous context : this ensures +- * that events detected in the previous context are purged. They will +- * be re-detected and processed in the new context. +- */ +-static void slave_update_read_handler(struct vhost_dev *dev, +- GMainContext *ctxt) +-{ +- struct vhost_user *u = dev->opaque; +- +- if (!u->slave_ioc) { +- return; +- } +- +- if (u->slave_src) { +- g_source_destroy(u->slave_src); +- g_source_unref(u->slave_src); +- } +- +- u->slave_src = qio_channel_add_watch_source(u->slave_ioc, +- G_IO_IN | G_IO_HUP, +- slave_read, dev, NULL, +- ctxt); +-} +- + static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) + { + struct vhost_user *u = dev->opaque; +@@ -406,7 +377,6 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) + * be prepared for re-entrancy. So we create a new one and switch chr + * to use it. + */ +- slave_update_read_handler(dev, ctxt); + qemu_chr_be_update_read_handlers(chr->chr, ctxt); + qemu_chr_fe_add_watch(chr, G_IO_IN | G_IO_HUP, vhost_user_read_cb, &data); + +@@ -418,7 +388,6 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) + * context that have been processed by the nested loop are purged. + */ + qemu_chr_be_update_read_handlers(chr->chr, prev_ctxt); +- slave_update_read_handler(dev, NULL); + + g_main_loop_unref(loop); + g_main_context_unref(ctxt); +@@ -1802,7 +1771,9 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev) + return -ECONNREFUSED; + } + u->slave_ioc = ioc; +- slave_update_read_handler(dev, NULL); ++ u->slave_src = qio_channel_add_watch_source(u->slave_ioc, ++ G_IO_IN | G_IO_HUP, ++ slave_read, dev, NULL, NULL); + + if (reply_supported) { + msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; +-- +2.31.1 + diff --git a/kvm-accel-tcg-Test-CPUJumpCache-in-tb_jmp_cache_clear_pa.patch b/kvm-accel-tcg-Test-CPUJumpCache-in-tb_jmp_cache_clear_pa.patch new file mode 100644 index 0000000..0680a26 --- /dev/null +++ b/kvm-accel-tcg-Test-CPUJumpCache-in-tb_jmp_cache_clear_pa.patch @@ -0,0 +1,58 @@ +From ab68e13b7628f2348d41a4518a92508542af712f Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Fri, 3 Feb 2023 18:15:10 +0100 +Subject: [PATCH 05/20] accel/tcg: Test CPUJumpCache in tb_jmp_cache_clear_page + +RH-Author: Eric Auger +RH-MergeRequest: 144: accel/tcg: Test CPUJumpCache in tb_jmp_cache_clear_page +RH-Bugzilla: 2165280 +RH-Acked-by: Cornelia Huck +RH-Acked-by: Gavin Shan +RH-Acked-by: Shaoqin Huang +RH-Commit: [1/1] 5b0863c34ba06c01c4e343d1ecd72402779c7de3 (eauger1/centos-qemu-kvm) + +Bugzilla: https://bugzilla.redhat.com/2165280 +Upstream: yes +Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=50530041 +Test: 'kvm unit test ./run_tests.sh -g debug' does not SIGSEV anymore + +After commit 4e4fa6c12d ("accel/tcg: Complete cpu initialization +before registration"), it looks the CPUJumpCache pointer can be NULL. +This causes a SIGSEV when running debug-wp-migration kvm unit test. + +At the first place it should be clarified why this TCG code is called +with KVM acceleration. This may hide another bug. + +Fixes: 4e4fa6c12d ("accel/tcg: Complete cpu initialization before registration") +Signed-off-by: Eric Auger +Message-Id: <20230203171510.2867451-1-eric.auger@redhat.com> +Signed-off-by: Richard Henderson +(cherry picked from commit 99ab4d500af638ba3ebb20e8aa89d72201b70860) +Signed-off-by: Eric Auger +--- + accel/tcg/cputlb.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c +index 6f1c00682b..4244b0e4e3 100644 +--- a/accel/tcg/cputlb.c ++++ b/accel/tcg/cputlb.c +@@ -100,9 +100,14 @@ static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns, + + static void tb_jmp_cache_clear_page(CPUState *cpu, target_ulong page_addr) + { +- int i, i0 = tb_jmp_cache_hash_page(page_addr); + CPUJumpCache *jc = cpu->tb_jmp_cache; ++ int i, i0; + ++ if (unlikely(!jc)) { ++ return; ++ } ++ ++ i0 = tb_jmp_cache_hash_page(page_addr); + for (i = 0; i < TB_JMP_PAGE_SIZE; i++) { + qatomic_set(&jc->array[i0 + i].tb, NULL); + } +-- +2.31.1 + diff --git a/kvm-block-Improve-empty-format-specific-info-dump.patch b/kvm-block-Improve-empty-format-specific-info-dump.patch new file mode 100644 index 0000000..5b54210 --- /dev/null +++ b/kvm-block-Improve-empty-format-specific-info-dump.patch @@ -0,0 +1,132 @@ +From 074c89b05dae971c7118cb769fd34e22135c8f4c Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:26:53 +0200 +Subject: [PATCH 06/20] block: Improve empty format-specific info dump + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [1/12] be551e83f426e620e673302198b51368bfd324ce (hreitz/qemu-kvm-c-9-s) + +When a block driver supports obtaining format-specific information, but +that object only contains optional fields, it is possible that none of +them are present, so that dump_qobject() (called by +bdrv_image_info_specific_dump()) will not print anything. + +The callers of bdrv_image_info_specific_dump() put a header above this +information ("Format specific information:\n"), which will look strange +when there is nothing below. Modify bdrv_image_info_specific_dump() to +print this header instead of its callers, and only if there is indeed +something to be printed. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-2-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 3716470b24f0f63090d59bcf28ad8fe6fb7835bd) +Signed-off-by: Hanna Czenczek +--- + block/qapi.c | 41 +++++++++++++++++++++++++++++++++++++---- + include/block/qapi.h | 3 ++- + qemu-io-cmds.c | 4 ++-- + 3 files changed, 41 insertions(+), 7 deletions(-) + +diff --git a/block/qapi.c b/block/qapi.c +index cf557e3aea..51202b470a 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -777,7 +777,35 @@ static void dump_qdict(int indentation, QDict *dict) + } + } + +-void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec) ++/* ++ * Return whether dumping the given QObject with dump_qobject() would ++ * yield an empty dump, i.e. not print anything. ++ */ ++static bool qobject_is_empty_dump(const QObject *obj) ++{ ++ switch (qobject_type(obj)) { ++ case QTYPE_QNUM: ++ case QTYPE_QSTRING: ++ case QTYPE_QBOOL: ++ return false; ++ ++ case QTYPE_QDICT: ++ return qdict_size(qobject_to(QDict, obj)) == 0; ++ ++ case QTYPE_QLIST: ++ return qlist_empty(qobject_to(QList, obj)); ++ ++ default: ++ abort(); ++ } ++} ++ ++/** ++ * Dumps the given ImageInfoSpecific object in a human-readable form, ++ * prepending an optional prefix if the dump is not empty. ++ */ ++void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, ++ const char *prefix) + { + QObject *obj, *data; + Visitor *v = qobject_output_visitor_new(&obj); +@@ -785,7 +813,12 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec) + visit_type_ImageInfoSpecific(v, NULL, &info_spec, &error_abort); + visit_complete(v, &obj); + data = qdict_get(qobject_to(QDict, obj), "data"); +- dump_qobject(1, data); ++ if (!qobject_is_empty_dump(data)) { ++ if (prefix) { ++ qemu_printf("%s", prefix); ++ } ++ dump_qobject(1, data); ++ } + qobject_unref(obj); + visit_free(v); + } +@@ -866,7 +899,7 @@ void bdrv_image_info_dump(ImageInfo *info) + } + + if (info->has_format_specific) { +- qemu_printf("Format specific information:\n"); +- bdrv_image_info_specific_dump(info->format_specific); ++ bdrv_image_info_specific_dump(info->format_specific, ++ "Format specific information:\n"); + } + } +diff --git a/include/block/qapi.h b/include/block/qapi.h +index 22c7807c89..c09859ea78 100644 +--- a/include/block/qapi.h ++++ b/include/block/qapi.h +@@ -40,6 +40,7 @@ void bdrv_query_image_info(BlockDriverState *bs, + Error **errp); + + void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); +-void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec); ++void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, ++ const char *prefix); + void bdrv_image_info_dump(ImageInfo *info); + #endif +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index 952dc940f1..f4a374528e 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -1825,8 +1825,8 @@ static int info_f(BlockBackend *blk, int argc, char **argv) + return -EIO; + } + if (spec_info) { +- printf("Format specific information:\n"); +- bdrv_image_info_specific_dump(spec_info); ++ bdrv_image_info_specific_dump(spec_info, ++ "Format specific information:\n"); + qapi_free_ImageInfoSpecific(spec_info); + } + +-- +2.31.1 + diff --git a/kvm-block-Split-BlockNodeInfo-off-of-ImageInfo.patch b/kvm-block-Split-BlockNodeInfo-off-of-ImageInfo.patch new file mode 100644 index 0000000..2d95689 --- /dev/null +++ b/kvm-block-Split-BlockNodeInfo-off-of-ImageInfo.patch @@ -0,0 +1,246 @@ +From 54e290df4bc1c9e83be7357caed6a2b1ba4f21f0 Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:26:56 +0200 +Subject: [PATCH 09/20] block: Split BlockNodeInfo off of ImageInfo + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [4/12] fc8d69d549bb9a929db218b91697ee3ae95c1ff6 (hreitz/qemu-kvm-c-9-s) + +ImageInfo sometimes contains flat information, and sometimes it does +not. Split off a BlockNodeInfo struct, which only contains information +about a single node and has no link to the backing image. + +We do this so we can extend BlockNodeInfo to a BlockGraphInfo struct, +which has links to all child nodes, not just the backing node. It would +be strange to base BlockGraphInfo on ImageInfo, because then this +extended struct would have two links to the backing node (one in +BlockGraphInfo as one of all the child links, and one in ImageInfo). + +Furthermore, it is quite common to ignore the backing-image field +altogether: bdrv_query_image_info() does not set it, and +bdrv_image_info_dump() does not evaluate it. That signals that we +should have different structs for describing a single node and one that +has a link to the backing image. + +Still, bdrv_query_image_info() and bdrv_image_info_dump() are not +changed too much in this patch. Follow-up patches will handle them. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-5-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit a2085f8909377b6df738f6c3f7ee6db4d16da8f7) +Signed-off-by: Hanna Czenczek +--- + block/qapi.c | 86 ++++++++++++++++++++++++++++++++------------ + include/block/qapi.h | 3 ++ + qapi/block-core.json | 24 +++++++++---- + 3 files changed, 85 insertions(+), 28 deletions(-) + +diff --git a/block/qapi.c b/block/qapi.c +index 51202b470a..e5022b4481 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -241,30 +241,18 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs, + } + + /** +- * bdrv_query_image_info: +- * @bs: block device to examine +- * @p_info: location to store image information +- * @errp: location to store error information +- * +- * Store "flat" image information in @p_info. +- * +- * "Flat" means it does *not* query backing image information, +- * i.e. (*pinfo)->has_backing_image will be set to false and +- * (*pinfo)->backing_image to NULL even when the image does in fact have +- * a backing image. +- * +- * @p_info will be set only on success. On error, store error in @errp. ++ * Helper function for other query info functions. Store information about @bs ++ * in @info, setting @errp on error. + */ +-void bdrv_query_image_info(BlockDriverState *bs, +- ImageInfo **p_info, +- Error **errp) ++static void bdrv_do_query_node_info(BlockDriverState *bs, ++ BlockNodeInfo *info, ++ Error **errp) + { + int64_t size; + const char *backing_filename; + BlockDriverInfo bdi; + int ret; + Error *err = NULL; +- ImageInfo *info; + + aio_context_acquire(bdrv_get_aio_context(bs)); + +@@ -277,7 +265,6 @@ void bdrv_query_image_info(BlockDriverState *bs, + + bdrv_refresh_filename(bs); + +- info = g_new0(ImageInfo, 1); + info->filename = g_strdup(bs->filename); + info->format = g_strdup(bdrv_get_format_name(bs)); + info->virtual_size = size; +@@ -298,7 +285,6 @@ void bdrv_query_image_info(BlockDriverState *bs, + info->format_specific = bdrv_get_specific_info(bs, &err); + if (err) { + error_propagate(errp, err); +- qapi_free_ImageInfo(info); + goto out; + } + info->has_format_specific = info->format_specific != NULL; +@@ -339,16 +325,72 @@ void bdrv_query_image_info(BlockDriverState *bs, + break; + default: + error_propagate(errp, err); +- qapi_free_ImageInfo(info); + goto out; + } + +- *p_info = info; +- + out: + aio_context_release(bdrv_get_aio_context(bs)); + } + ++/** ++ * bdrv_query_block_node_info: ++ * @bs: block node to examine ++ * @p_info: location to store node information ++ * @errp: location to store error information ++ * ++ * Store image information about @bs in @p_info. ++ * ++ * @p_info will be set only on success. On error, store error in @errp. ++ */ ++void bdrv_query_block_node_info(BlockDriverState *bs, ++ BlockNodeInfo **p_info, ++ Error **errp) ++{ ++ BlockNodeInfo *info; ++ ERRP_GUARD(); ++ ++ info = g_new0(BlockNodeInfo, 1); ++ bdrv_do_query_node_info(bs, info, errp); ++ if (*errp) { ++ qapi_free_BlockNodeInfo(info); ++ return; ++ } ++ ++ *p_info = info; ++} ++ ++/** ++ * bdrv_query_image_info: ++ * @bs: block node to examine ++ * @p_info: location to store image information ++ * @errp: location to store error information ++ * ++ * Store "flat" image information in @p_info. ++ * ++ * "Flat" means it does *not* query backing image information, ++ * i.e. (*pinfo)->has_backing_image will be set to false and ++ * (*pinfo)->backing_image to NULL even when the image does in fact have ++ * a backing image. ++ * ++ * @p_info will be set only on success. On error, store error in @errp. ++ */ ++void bdrv_query_image_info(BlockDriverState *bs, ++ ImageInfo **p_info, ++ Error **errp) ++{ ++ ImageInfo *info; ++ ERRP_GUARD(); ++ ++ info = g_new0(ImageInfo, 1); ++ bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), errp); ++ if (*errp) { ++ qapi_free_ImageInfo(info); ++ return; ++ } ++ ++ *p_info = info; ++} ++ + /* @p_info will be set only on success. */ + static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, + Error **errp) +diff --git a/include/block/qapi.h b/include/block/qapi.h +index c09859ea78..c7de4e3fa9 100644 +--- a/include/block/qapi.h ++++ b/include/block/qapi.h +@@ -35,6 +35,9 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, + int bdrv_query_snapshot_info_list(BlockDriverState *bs, + SnapshotInfoList **p_list, + Error **errp); ++void bdrv_query_block_node_info(BlockDriverState *bs, ++ BlockNodeInfo **p_info, ++ Error **errp); + void bdrv_query_image_info(BlockDriverState *bs, + ImageInfo **p_info, + Error **errp); +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 4b9365167f..7720da0498 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -251,7 +251,7 @@ + } } + + ## +-# @ImageInfo: ++# @BlockNodeInfo: + # + # Information about a QEMU image file + # +@@ -279,22 +279,34 @@ + # + # @snapshots: list of VM snapshots + # +-# @backing-image: info of the backing image (since 1.6) +-# + # @format-specific: structure supplying additional format-specific + # information (since 1.7) + # +-# Since: 1.3 ++# Since: 8.0 + ## +-{ 'struct': 'ImageInfo', ++{ 'struct': 'BlockNodeInfo', + 'data': {'filename': 'str', 'format': 'str', '*dirty-flag': 'bool', + '*actual-size': 'int', 'virtual-size': 'int', + '*cluster-size': 'int', '*encrypted': 'bool', '*compressed': 'bool', + '*backing-filename': 'str', '*full-backing-filename': 'str', + '*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'], +- '*backing-image': 'ImageInfo', + '*format-specific': 'ImageInfoSpecific' } } + ++## ++# @ImageInfo: ++# ++# Information about a QEMU image file, and potentially its backing image ++# ++# @backing-image: info of the backing image ++# ++# Since: 1.3 ++## ++{ 'struct': 'ImageInfo', ++ 'base': 'BlockNodeInfo', ++ 'data': { ++ '*backing-image': 'ImageInfo' ++ } } ++ + ## + # @ImageCheck: + # +-- +2.31.1 + diff --git a/kvm-block-file-Add-file-specific-image-info.patch b/kvm-block-file-Add-file-specific-image-info.patch new file mode 100644 index 0000000..a81b6b0 --- /dev/null +++ b/kvm-block-file-Add-file-specific-image-info.patch @@ -0,0 +1,145 @@ +From 4af86458d6bea2a6e15fd57d4d4bbe88e35f7e72 Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:26:54 +0200 +Subject: [PATCH 07/20] block/file: Add file-specific image info + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [2/12] d8cc351d6c16c41b2000e41dc555f13093a9edce (hreitz/qemu-kvm-c-9-s) + +Add some (optional) information that the file driver can provide for +image files, namely the extent size hint. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-3-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 7f36a50ab4e7d39369cac67be4ba9d6ee4081dc0) +Signed-off-by: Hanna Czenczek +--- + block/file-posix.c | 30 ++++++++++++++++++++++++++++++ + qapi/block-core.json | 26 ++++++++++++++++++++++++-- + 2 files changed, 54 insertions(+), 2 deletions(-) + +diff --git a/block/file-posix.c b/block/file-posix.c +index b9647c5ffc..df3da79aed 100644 +--- a/block/file-posix.c ++++ b/block/file-posix.c +@@ -3095,6 +3095,34 @@ static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) + return 0; + } + ++static ImageInfoSpecific *raw_get_specific_info(BlockDriverState *bs, ++ Error **errp) ++{ ++ ImageInfoSpecificFile *file_info = g_new0(ImageInfoSpecificFile, 1); ++ ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1); ++ ++ *spec_info = (ImageInfoSpecific){ ++ .type = IMAGE_INFO_SPECIFIC_KIND_FILE, ++ .u.file.data = file_info, ++ }; ++ ++#ifdef FS_IOC_FSGETXATTR ++ { ++ BDRVRawState *s = bs->opaque; ++ struct fsxattr attr; ++ int ret; ++ ++ ret = ioctl(s->fd, FS_IOC_FSGETXATTR, &attr); ++ if (!ret && attr.fsx_extsize != 0) { ++ file_info->has_extent_size_hint = true; ++ file_info->extent_size_hint = attr.fsx_extsize; ++ } ++ } ++#endif ++ ++ return spec_info; ++} ++ + static BlockStatsSpecificFile get_blockstats_specific_file(BlockDriverState *bs) + { + BDRVRawState *s = bs->opaque; +@@ -3328,6 +3356,7 @@ BlockDriver bdrv_file = { + .bdrv_co_truncate = raw_co_truncate, + .bdrv_getlength = raw_getlength, + .bdrv_get_info = raw_get_info, ++ .bdrv_get_specific_info = raw_get_specific_info, + .bdrv_get_allocated_file_size + = raw_get_allocated_file_size, + .bdrv_get_specific_stats = raw_get_specific_stats, +@@ -3700,6 +3729,7 @@ static BlockDriver bdrv_host_device = { + .bdrv_co_truncate = raw_co_truncate, + .bdrv_getlength = raw_getlength, + .bdrv_get_info = raw_get_info, ++ .bdrv_get_specific_info = raw_get_specific_info, + .bdrv_get_allocated_file_size + = raw_get_allocated_file_size, + .bdrv_get_specific_stats = hdev_get_specific_stats, +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 95ac4fa634..f5d822cbd6 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -139,16 +139,29 @@ + '*encryption-format': 'RbdImageEncryptionFormat' + } } + ++## ++# @ImageInfoSpecificFile: ++# ++# @extent-size-hint: Extent size hint (if available) ++# ++# Since: 8.0 ++## ++{ 'struct': 'ImageInfoSpecificFile', ++ 'data': { ++ '*extent-size-hint': 'size' ++ } } ++ + ## + # @ImageInfoSpecificKind: + # + # @luks: Since 2.7 + # @rbd: Since 6.1 ++# @file: Since 8.0 + # + # Since: 1.7 + ## + { 'enum': 'ImageInfoSpecificKind', +- 'data': [ 'qcow2', 'vmdk', 'luks', 'rbd' ] } ++ 'data': [ 'qcow2', 'vmdk', 'luks', 'rbd', 'file' ] } + + ## + # @ImageInfoSpecificQCow2Wrapper: +@@ -185,6 +198,14 @@ + { 'struct': 'ImageInfoSpecificRbdWrapper', + 'data': { 'data': 'ImageInfoSpecificRbd' } } + ++## ++# @ImageInfoSpecificFileWrapper: ++# ++# Since: 8.0 ++## ++{ 'struct': 'ImageInfoSpecificFileWrapper', ++ 'data': { 'data': 'ImageInfoSpecificFile' } } ++ + ## + # @ImageInfoSpecific: + # +@@ -199,7 +220,8 @@ + 'qcow2': 'ImageInfoSpecificQCow2Wrapper', + 'vmdk': 'ImageInfoSpecificVmdkWrapper', + 'luks': 'ImageInfoSpecificLUKSWrapper', +- 'rbd': 'ImageInfoSpecificRbdWrapper' ++ 'rbd': 'ImageInfoSpecificRbdWrapper', ++ 'file': 'ImageInfoSpecificFileWrapper' + } } + + ## +-- +2.31.1 + diff --git a/kvm-block-qapi-Add-indentation-to-bdrv_node_info_dump.patch b/kvm-block-qapi-Add-indentation-to-bdrv_node_info_dump.patch new file mode 100644 index 0000000..62979ef --- /dev/null +++ b/kvm-block-qapi-Add-indentation-to-bdrv_node_info_dump.patch @@ -0,0 +1,206 @@ +From c8c282c2e1d74cfc5de6527f7e20dfc3e76b67ac Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:27:00 +0200 +Subject: [PATCH 13/20] block/qapi: Add indentation to bdrv_node_info_dump() + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [8/12] d3a697e81ab9828457198075e5815a592363c725 (hreitz/qemu-kvm-c-9-s) + +In order to let qemu-img info present a block graph, add a parameter to +bdrv_node_info_dump() and bdrv_image_info_specific_dump() so that the +information of nodes below the root level can be given an indentation. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-9-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 76c9e9750d1bd580e8ed4465f6be3a986434e7c3) +Signed-off-by: Hanna Czenczek +--- + block/monitor/block-hmp-cmds.c | 2 +- + block/qapi.c | 47 +++++++++++++++++++--------------- + include/block/qapi.h | 5 ++-- + qemu-img.c | 2 +- + qemu-io-cmds.c | 3 ++- + 5 files changed, 34 insertions(+), 25 deletions(-) + +diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c +index aa37faa601..72824d4e2e 100644 +--- a/block/monitor/block-hmp-cmds.c ++++ b/block/monitor/block-hmp-cmds.c +@@ -734,7 +734,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, + monitor_printf(mon, "\nImages:\n"); + image_info = inserted->image; + while (1) { +- bdrv_node_info_dump(qapi_ImageInfo_base(image_info)); ++ bdrv_node_info_dump(qapi_ImageInfo_base(image_info), 0); + if (image_info->has_backing_image) { + image_info = image_info->backing_image; + } else { +diff --git a/block/qapi.c b/block/qapi.c +index f208c21ccf..3e35603f0c 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -915,7 +915,8 @@ static bool qobject_is_empty_dump(const QObject *obj) + * prepending an optional prefix if the dump is not empty. + */ + void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, +- const char *prefix) ++ const char *prefix, ++ int indentation) + { + QObject *obj, *data; + Visitor *v = qobject_output_visitor_new(&obj); +@@ -925,48 +926,51 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, + data = qdict_get(qobject_to(QDict, obj), "data"); + if (!qobject_is_empty_dump(data)) { + if (prefix) { +- qemu_printf("%s", prefix); ++ qemu_printf("%*s%s", indentation * 4, "", prefix); + } +- dump_qobject(1, data); ++ dump_qobject(indentation + 1, data); + } + qobject_unref(obj); + visit_free(v); + } + +-void bdrv_node_info_dump(BlockNodeInfo *info) ++void bdrv_node_info_dump(BlockNodeInfo *info, int indentation) + { + char *size_buf, *dsize_buf; ++ g_autofree char *ind_s = g_strdup_printf("%*s", indentation * 4, ""); ++ + if (!info->has_actual_size) { + dsize_buf = g_strdup("unavailable"); + } else { + dsize_buf = size_to_str(info->actual_size); + } + size_buf = size_to_str(info->virtual_size); +- qemu_printf("image: %s\n" +- "file format: %s\n" +- "virtual size: %s (%" PRId64 " bytes)\n" +- "disk size: %s\n", +- info->filename, info->format, size_buf, +- info->virtual_size, +- dsize_buf); ++ qemu_printf("%simage: %s\n" ++ "%sfile format: %s\n" ++ "%svirtual size: %s (%" PRId64 " bytes)\n" ++ "%sdisk size: %s\n", ++ ind_s, info->filename, ++ ind_s, info->format, ++ ind_s, size_buf, info->virtual_size, ++ ind_s, dsize_buf); + g_free(size_buf); + g_free(dsize_buf); + + if (info->has_encrypted && info->encrypted) { +- qemu_printf("encrypted: yes\n"); ++ qemu_printf("%sencrypted: yes\n", ind_s); + } + + if (info->has_cluster_size) { +- qemu_printf("cluster_size: %" PRId64 "\n", +- info->cluster_size); ++ qemu_printf("%scluster_size: %" PRId64 "\n", ++ ind_s, info->cluster_size); + } + + if (info->has_dirty_flag && info->dirty_flag) { +- qemu_printf("cleanly shut down: no\n"); ++ qemu_printf("%scleanly shut down: no\n", ind_s); + } + + if (info->has_backing_filename) { +- qemu_printf("backing file: %s", info->backing_filename); ++ qemu_printf("%sbacking file: %s", ind_s, info->backing_filename); + if (!info->has_full_backing_filename) { + qemu_printf(" (cannot determine actual path)"); + } else if (strcmp(info->backing_filename, +@@ -975,15 +979,16 @@ void bdrv_node_info_dump(BlockNodeInfo *info) + } + qemu_printf("\n"); + if (info->has_backing_filename_format) { +- qemu_printf("backing file format: %s\n", +- info->backing_filename_format); ++ qemu_printf("%sbacking file format: %s\n", ++ ind_s, info->backing_filename_format); + } + } + + if (info->has_snapshots) { + SnapshotInfoList *elem; + +- qemu_printf("Snapshot list:\n"); ++ qemu_printf("%sSnapshot list:\n", ind_s); ++ qemu_printf("%s", ind_s); + bdrv_snapshot_dump(NULL); + qemu_printf("\n"); + +@@ -1003,6 +1008,7 @@ void bdrv_node_info_dump(BlockNodeInfo *info) + + pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id); + pstrcpy(sn.name, sizeof(sn.name), elem->value->name); ++ qemu_printf("%s", ind_s); + bdrv_snapshot_dump(&sn); + qemu_printf("\n"); + } +@@ -1010,6 +1016,7 @@ void bdrv_node_info_dump(BlockNodeInfo *info) + + if (info->has_format_specific) { + bdrv_image_info_specific_dump(info->format_specific, +- "Format specific information:\n"); ++ "Format specific information:\n", ++ indentation); + } + } +diff --git a/include/block/qapi.h b/include/block/qapi.h +index 196436020e..38855f2ae9 100644 +--- a/include/block/qapi.h ++++ b/include/block/qapi.h +@@ -49,6 +49,7 @@ void bdrv_query_block_graph_info(BlockDriverState *bs, + + void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); + void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, +- const char *prefix); +-void bdrv_node_info_dump(BlockNodeInfo *info); ++ const char *prefix, ++ int indentation); ++void bdrv_node_info_dump(BlockNodeInfo *info, int indentation); + #endif +diff --git a/qemu-img.c b/qemu-img.c +index 3b2ca3bbcb..30b4ea58bb 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2859,7 +2859,7 @@ static void dump_human_image_info_list(BlockNodeInfoList *list) + } + delim = true; + +- bdrv_node_info_dump(elem->value); ++ bdrv_node_info_dump(elem->value, 0); + } + } + +diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c +index f4a374528e..fdcb89211b 100644 +--- a/qemu-io-cmds.c ++++ b/qemu-io-cmds.c +@@ -1826,7 +1826,8 @@ static int info_f(BlockBackend *blk, int argc, char **argv) + } + if (spec_info) { + bdrv_image_info_specific_dump(spec_info, +- "Format specific information:\n"); ++ "Format specific information:\n", ++ 0); + qapi_free_ImageInfoSpecific(spec_info); + } + +-- +2.31.1 + diff --git a/kvm-block-qapi-Introduce-BlockGraphInfo.patch b/kvm-block-qapi-Introduce-BlockGraphInfo.patch new file mode 100644 index 0000000..e9a1622 --- /dev/null +++ b/kvm-block-qapi-Introduce-BlockGraphInfo.patch @@ -0,0 +1,155 @@ +From 0044e3848b02ef6edba5961d1f4b6297d137d207 Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:26:59 +0200 +Subject: [PATCH 12/20] block/qapi: Introduce BlockGraphInfo + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [7/12] de47bac372cd552b812c774a2f35f95923af74ff (hreitz/qemu-kvm-c-9-s) + +Introduce a new QAPI type BlockGraphInfo and an associated +bdrv_query_block_graph_info() function that recursively gathers +BlockNodeInfo objects through a block graph. + +A follow-up patch is going to make "qemu-img info" use this to print +information about all nodes that are (usually implicitly) opened for a +given image file. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-8-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 6cab33997b91eb86e82a6a2ae58a24f835249d4a) +Signed-off-by: Hanna Czenczek +--- + block/qapi.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ + include/block/qapi.h | 3 +++ + qapi/block-core.json | 35 ++++++++++++++++++++++++++++++++ + 3 files changed, 86 insertions(+) + +diff --git a/block/qapi.c b/block/qapi.c +index 5d0a8d2ce3..f208c21ccf 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -411,6 +411,54 @@ fail: + qapi_free_ImageInfo(info); + } + ++/** ++ * bdrv_query_block_graph_info: ++ * @bs: root node to start from ++ * @p_info: location to store image information ++ * @errp: location to store error information ++ * ++ * Store image information about the graph starting from @bs in @p_info. ++ * ++ * @p_info will be set only on success. On error, store error in @errp. ++ */ ++void bdrv_query_block_graph_info(BlockDriverState *bs, ++ BlockGraphInfo **p_info, ++ Error **errp) ++{ ++ BlockGraphInfo *info; ++ BlockChildInfoList **children_list_tail; ++ BdrvChild *c; ++ ERRP_GUARD(); ++ ++ info = g_new0(BlockGraphInfo, 1); ++ bdrv_do_query_node_info(bs, qapi_BlockGraphInfo_base(info), errp); ++ if (*errp) { ++ goto fail; ++ } ++ ++ children_list_tail = &info->children; ++ ++ QLIST_FOREACH(c, &bs->children, next) { ++ BlockChildInfo *c_info; ++ ++ c_info = g_new0(BlockChildInfo, 1); ++ QAPI_LIST_APPEND(children_list_tail, c_info); ++ ++ c_info->name = g_strdup(c->name); ++ bdrv_query_block_graph_info(c->bs, &c_info->info, errp); ++ if (*errp) { ++ goto fail; ++ } ++ } ++ ++ *p_info = info; ++ return; ++ ++fail: ++ assert(*errp != NULL); ++ qapi_free_BlockGraphInfo(info); ++} ++ + /* @p_info will be set only on success. */ + static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, + Error **errp) +diff --git a/include/block/qapi.h b/include/block/qapi.h +index 2174bf8fa2..196436020e 100644 +--- a/include/block/qapi.h ++++ b/include/block/qapi.h +@@ -43,6 +43,9 @@ void bdrv_query_image_info(BlockDriverState *bs, + bool flat, + bool skip_implicit_filters, + Error **errp); ++void bdrv_query_block_graph_info(BlockDriverState *bs, ++ BlockGraphInfo **p_info, ++ Error **errp); + + void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); + void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 4cf2deeb6c..d703e0fb16 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -307,6 +307,41 @@ + '*backing-image': 'ImageInfo' + } } + ++## ++# @BlockChildInfo: ++# ++# Information about all nodes in the block graph starting at some node, ++# annotated with information about that node in relation to its parent. ++# ++# @name: Child name of the root node in the BlockGraphInfo struct, in its role ++# as the child of some undescribed parent node ++# ++# @info: Block graph information starting at this node ++# ++# Since: 8.0 ++## ++{ 'struct': 'BlockChildInfo', ++ 'data': { ++ 'name': 'str', ++ 'info': 'BlockGraphInfo' ++ } } ++ ++## ++# @BlockGraphInfo: ++# ++# Information about all nodes in a block (sub)graph in the form of BlockNodeInfo ++# data. ++# The base BlockNodeInfo struct contains the information for the (sub)graph's ++# root node. ++# ++# @children: Array of links to this node's child nodes' information ++# ++# Since: 8.0 ++## ++{ 'struct': 'BlockGraphInfo', ++ 'base': 'BlockNodeInfo', ++ 'data': { 'children': ['BlockChildInfo'] } } ++ + ## + # @ImageCheck: + # +-- +2.31.1 + diff --git a/kvm-block-qapi-Let-bdrv_query_image_info-recurse.patch b/kvm-block-qapi-Let-bdrv_query_image_info-recurse.patch new file mode 100644 index 0000000..e5c012a --- /dev/null +++ b/kvm-block-qapi-Let-bdrv_query_image_info-recurse.patch @@ -0,0 +1,197 @@ +From ae2c3df00d673d436fe4d8ec9103a3b76d7e6233 Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:26:58 +0200 +Subject: [PATCH 11/20] block/qapi: Let bdrv_query_image_info() recurse + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [6/12] 451a83fd682cd6dd6026c22974d18c2f12ee06e3 (hreitz/qemu-kvm-c-9-s) + +There is no real reason why bdrv_query_image_info() should generally not +recurse. The ImageInfo struct has a pointer to the backing image, so it +should generally be filled, unless the caller explicitly opts out. + +This moves the recursing code from bdrv_block_device_info() into +bdrv_query_image_info(). + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-7-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 5d8813593f3f673fc96eed199beb35690cc46f58) + +Conflicts: + block/qapi.c: Conflicts with + 54fde4ff0621c22b15cbaaa3c74301cc0dbd1c9e ("qapi block: Elide + redundant has_FOO in generated C"), which dropped + `has_backing_image`. Without that commit (and 44ea9d9be before it), + we still need to set `has_backing_image` in + `bdrv_query_image_info()`. + +Signed-off-by: Hanna Czenczek +--- + block/qapi.c | 94 +++++++++++++++++++++++++++----------------- + include/block/qapi.h | 2 + + 2 files changed, 59 insertions(+), 37 deletions(-) + +diff --git a/block/qapi.c b/block/qapi.c +index ad88bf9b38..5d0a8d2ce3 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -47,8 +47,10 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, + Error **errp) + { + ImageInfo **p_image_info; ++ ImageInfo *backing_info; + BlockDriverState *bs0, *backing; + BlockDeviceInfo *info; ++ ERRP_GUARD(); + + if (!bs->drv) { + error_setg(errp, "Block device %s is ejected", bs->node_name); +@@ -149,38 +151,21 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, + bs0 = bs; + p_image_info = &info->image; + info->backing_file_depth = 0; +- while (1) { +- Error *local_err = NULL; +- bdrv_query_image_info(bs0, p_image_info, &local_err); +- if (local_err) { +- error_propagate(errp, local_err); +- qapi_free_BlockDeviceInfo(info); +- return NULL; +- } +- +- /* stop gathering data for flat output */ +- if (flat) { +- break; +- } + +- if (bs0->drv && bdrv_filter_or_cow_child(bs0)) { +- /* +- * Put any filtered child here (for backwards compatibility to when +- * we put bs0->backing here, which might be any filtered child). +- */ +- info->backing_file_depth++; +- bs0 = bdrv_filter_or_cow_bs(bs0); +- (*p_image_info)->has_backing_image = true; +- p_image_info = &((*p_image_info)->backing_image); +- } else { +- break; +- } ++ /* ++ * Skip automatically inserted nodes that the user isn't aware of for ++ * query-block (blk != NULL), but not for query-named-block-nodes ++ */ ++ bdrv_query_image_info(bs0, p_image_info, flat, blk != NULL, errp); ++ if (*errp) { ++ qapi_free_BlockDeviceInfo(info); ++ return NULL; ++ } + +- /* Skip automatically inserted nodes that the user isn't aware of for +- * query-block (blk != NULL), but not for query-named-block-nodes */ +- if (blk) { +- bs0 = bdrv_skip_implicit_filters(bs0); +- } ++ backing_info = info->image->backing_image; ++ while (backing_info) { ++ info->backing_file_depth++; ++ backing_info = backing_info->backing_image; + } + + return info; +@@ -363,19 +348,28 @@ void bdrv_query_block_node_info(BlockDriverState *bs, + * bdrv_query_image_info: + * @bs: block node to examine + * @p_info: location to store image information ++ * @flat: skip backing node information ++ * @skip_implicit_filters: skip implicit filters in the backing chain + * @errp: location to store error information + * +- * Store "flat" image information in @p_info. ++ * Store image information in @p_info, potentially recursively covering the ++ * backing chain. + * +- * "Flat" means it does *not* query backing image information, +- * i.e. (*pinfo)->has_backing_image will be set to false and +- * (*pinfo)->backing_image to NULL even when the image does in fact have +- * a backing image. ++ * If @flat is true, do not query backing image information, i.e. ++ * (*p_info)->has_backing_image will be set to false and ++ * (*p_info)->backing_image to NULL even when the image does in fact have a ++ * backing image. ++ * ++ * If @skip_implicit_filters is true, implicit filter nodes in the backing chain ++ * will be skipped when querying backing image information. ++ * (@skip_implicit_filters is ignored when @flat is true.) + * + * @p_info will be set only on success. On error, store error in @errp. + */ + void bdrv_query_image_info(BlockDriverState *bs, + ImageInfo **p_info, ++ bool flat, ++ bool skip_implicit_filters, + Error **errp) + { + ImageInfo *info; +@@ -384,11 +378,37 @@ void bdrv_query_image_info(BlockDriverState *bs, + info = g_new0(ImageInfo, 1); + bdrv_do_query_node_info(bs, qapi_ImageInfo_base(info), errp); + if (*errp) { +- qapi_free_ImageInfo(info); +- return; ++ goto fail; ++ } ++ ++ if (!flat) { ++ BlockDriverState *backing; ++ ++ /* ++ * Use any filtered child here (for backwards compatibility to when ++ * we always took bs->backing, which might be any filtered child). ++ */ ++ backing = bdrv_filter_or_cow_bs(bs); ++ if (skip_implicit_filters) { ++ backing = bdrv_skip_implicit_filters(backing); ++ } ++ ++ if (backing) { ++ bdrv_query_image_info(backing, &info->backing_image, false, ++ skip_implicit_filters, errp); ++ if (*errp) { ++ goto fail; ++ } ++ info->has_backing_image = true; ++ } + } + + *p_info = info; ++ return; ++ ++fail: ++ assert(*errp); ++ qapi_free_ImageInfo(info); + } + + /* @p_info will be set only on success. */ +diff --git a/include/block/qapi.h b/include/block/qapi.h +index 22198dcd0c..2174bf8fa2 100644 +--- a/include/block/qapi.h ++++ b/include/block/qapi.h +@@ -40,6 +40,8 @@ void bdrv_query_block_node_info(BlockDriverState *bs, + Error **errp); + void bdrv_query_image_info(BlockDriverState *bs, + ImageInfo **p_info, ++ bool flat, ++ bool skip_implicit_filters, + Error **errp); + + void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); +-- +2.31.1 + diff --git a/kvm-block-vmdk-Change-extent-info-type.patch b/kvm-block-vmdk-Change-extent-info-type.patch new file mode 100644 index 0000000..6b8f6a7 --- /dev/null +++ b/kvm-block-vmdk-Change-extent-info-type.patch @@ -0,0 +1,140 @@ +From d8caed018afb0f60f449e971398d2a8d6c2992e7 Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:26:55 +0200 +Subject: [PATCH 08/20] block/vmdk: Change extent info type + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [3/12] efe50a2797c679ce6bb5faa423047461a34e6792 (hreitz/qemu-kvm-c-9-s) + +VMDK's implementation of .bdrv_get_specific_info() returns information +about its extent files, ostensibly in the form of ImageInfo objects. +However, it does not get this information through +bdrv_query_image_info(), but fills only a select few fields with custom +information that does not always match the fields' purposes. + +For example, @format, which is supposed to be a block driver name, is +filled with the extent type, e.g. SPARSE or FLAT. + +In ImageInfo, @compressed shows whether the data that can be seen in the +image is stored in compressed form or not. For example, a compressed +qcow2 image will store compressed data in its data file, but when +accessing the qcow2 node, you will see normal data. This is not how +VMDK uses the @compressed field for its extent files: Instead, it +signifies whether accessing the extent file will yield compressed data +(which the VMDK driver then (de-)compresses). + +Create a new structure to represent the extent information. This allows +us to clarify the fields' meanings, and it clearly shows that these are +not complete ImageInfo objects. (That is, if a user wants an extent +file's ImageInfo object, they will need to query it separately, and will +not get it from ImageInfoSpecificVmdk.extents.) + +Note that this removes the last use of ['ImageInfo'] (i.e. an array of +ImageInfo objects), so the QAPI generator will no longer generate +ImageInfoList by default. However, we use it in qemu-img.c, so we need +to create a dummy object to force the generate to create that type, +similarly to DummyForceArrays in machine.json (introduced in commit +9f08c8ec73878122ad4b061ed334f0437afaaa32 ("qapi: Lazy creation of array +types")). + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-4-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 456e75171a85c19a5bfa202eefcbdc4ef1692f05) +Signed-off-by: Hanna Czenczek +--- + block/vmdk.c | 8 ++++---- + qapi/block-core.json | 38 +++++++++++++++++++++++++++++++++++++- + 2 files changed, 41 insertions(+), 5 deletions(-) + +diff --git a/block/vmdk.c b/block/vmdk.c +index 26376352b9..4435b9880b 100644 +--- a/block/vmdk.c ++++ b/block/vmdk.c +@@ -2901,12 +2901,12 @@ static int vmdk_has_zero_init(BlockDriverState *bs) + return 1; + } + +-static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) ++static VmdkExtentInfo *vmdk_get_extent_info(VmdkExtent *extent) + { +- ImageInfo *info = g_new0(ImageInfo, 1); ++ VmdkExtentInfo *info = g_new0(VmdkExtentInfo, 1); + + bdrv_refresh_filename(extent->file->bs); +- *info = (ImageInfo){ ++ *info = (VmdkExtentInfo){ + .filename = g_strdup(extent->file->bs->filename), + .format = g_strdup(extent->type), + .virtual_size = extent->sectors * BDRV_SECTOR_SIZE, +@@ -2985,7 +2985,7 @@ static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs, + int i; + BDRVVmdkState *s = bs->opaque; + ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1); +- ImageInfoList **tail; ++ VmdkExtentInfoList **tail; + + *spec_info = (ImageInfoSpecific){ + .type = IMAGE_INFO_SPECIFIC_KIND_VMDK, +diff --git a/qapi/block-core.json b/qapi/block-core.json +index f5d822cbd6..4b9365167f 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -124,7 +124,33 @@ + 'create-type': 'str', + 'cid': 'int', + 'parent-cid': 'int', +- 'extents': ['ImageInfo'] ++ 'extents': ['VmdkExtentInfo'] ++ } } ++ ++## ++# @VmdkExtentInfo: ++# ++# Information about a VMDK extent file ++# ++# @filename: Name of the extent file ++# ++# @format: Extent type (e.g. FLAT or SPARSE) ++# ++# @virtual-size: Number of bytes covered by this extent ++# ++# @cluster-size: Cluster size in bytes (for non-flat extents) ++# ++# @compressed: Whether this extent contains compressed data ++# ++# Since: 8.0 ++## ++{ 'struct': 'VmdkExtentInfo', ++ 'data': { ++ 'filename': 'str', ++ 'format': 'str', ++ 'virtual-size': 'int', ++ '*cluster-size': 'int', ++ '*compressed': 'bool' + } } + + ## +@@ -5754,3 +5780,13 @@ + 'data': { 'device': 'str', '*id': 'str', '*name': 'str'}, + 'returns': 'SnapshotInfo', + 'allow-preconfig': true } ++ ++## ++# @DummyBlockCoreForceArrays: ++# ++# Not used by QMP; hack to let us use ImageInfoList internally ++# ++# Since: 8.0 ++## ++{ 'struct': 'DummyBlockCoreForceArrays', ++ 'data': { 'unused-image-info': ['ImageInfo'] } } +-- +2.31.1 + diff --git a/kvm-iotests-106-214-308-Read-only-one-size-line.patch b/kvm-iotests-106-214-308-Read-only-one-size-line.patch new file mode 100644 index 0000000..399acfc --- /dev/null +++ b/kvm-iotests-106-214-308-Read-only-one-size-line.patch @@ -0,0 +1,99 @@ +From 6727e92a97f8ee9f367a41111bef3f5cad4a479a Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:27:02 +0200 +Subject: [PATCH 15/20] iotests/106, 214, 308: Read only one size line + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [10/12] 1554e0a92b92ed101a251478ccae43f45f6e071e (hreitz/qemu-kvm-c-9-s) + +These tests read size information (sometimes disk size, sometimes +virtual size) from qemu-img info's output. Once qemu-img starts +printing info about child nodes, we are going to see multiple instances +of that per image, but these tests are only interested in the first one, +so use "head -n 1" to get it. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-11-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 74163adda3101b127943f7cbbf8fcccd2d472426) +Signed-off-by: Hanna Czenczek +--- + tests/qemu-iotests/106 | 4 ++-- + tests/qemu-iotests/214 | 6 ++++-- + tests/qemu-iotests/308 | 4 ++-- + 3 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 +index 9d6adb542d..ae0fc46691 100755 +--- a/tests/qemu-iotests/106 ++++ b/tests/qemu-iotests/106 +@@ -66,7 +66,7 @@ for create_mode in off falloc full; do + expected_size=$((expected_size + $GROWTH_SIZE)) + fi + +- actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size') ++ actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size' | head -n 1) + actual_size=$(echo "$actual_size" | sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/') + + # The actual size may exceed the expected size, depending on the file +@@ -105,7 +105,7 @@ for growth_mode in falloc full; do + _make_test_img -o "extent_size_hint=0" 2G + $QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K + +- actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size') ++ actual_size=$($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep 'disk size' | head -n 1) + actual_size=$(echo "$actual_size" | sed -e 's/^[^0-9]*\([0-9]\+\).*$/\1/') + + if [ $actual_size -lt $GROWTH_SIZE ]; then +diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214 +index c66e246ba2..55ffcd7f44 100755 +--- a/tests/qemu-iotests/214 ++++ b/tests/qemu-iotests/214 +@@ -102,7 +102,8 @@ let data_size="8 * $cluster_size" + $QEMU_IO -c "write -P 0xaa 0 $data_size" "$TEST_IMG" \ + 2>&1 | _filter_qemu_io | _filter_testdir + sizeA=$($QEMU_IMG info --output=json "$TEST_IMG" | +- sed -n '/"actual-size":/ s/[^0-9]//gp') ++ sed -n '/"actual-size":/ s/[^0-9]//gp' | ++ head -n 1) + + _make_test_img 2M -o cluster_size=$cluster_size + echo "Write compressed data:" +@@ -124,7 +125,8 @@ $QEMU_IO -c "write -P 0xcc $offset $data_size" "json:{\ + _filter_qemu_io | _filter_testdir + + sizeB=$($QEMU_IMG info --output=json "$TEST_IMG" | +- sed -n '/"actual-size":/ s/[^0-9]//gp') ++ sed -n '/"actual-size":/ s/[^0-9]//gp' | ++ head -n 1) + + if [ $sizeA -lt $sizeB ] + then +diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 +index bde4aac2fa..09275e9a10 100755 +--- a/tests/qemu-iotests/308 ++++ b/tests/qemu-iotests/308 +@@ -217,12 +217,12 @@ echo + echo '=== Remove export ===' + + # Double-check that $EXT_MP appears as a non-empty file (the raw image) +-$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' ++$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' | head -n 1 + + fuse_export_del 'export-mp' + + # See that the file appears empty again +-$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' ++$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' | head -n 1 + + echo + echo '=== Writable export ===' +-- +2.31.1 + diff --git a/kvm-iotests-Filter-child-node-information.patch b/kvm-iotests-Filter-child-node-information.patch new file mode 100644 index 0000000..12eee3a --- /dev/null +++ b/kvm-iotests-Filter-child-node-information.patch @@ -0,0 +1,171 @@ +From 3102e62f80757729c97e58e2b3d62a6a9de952a7 Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:27:01 +0200 +Subject: [PATCH 14/20] iotests: Filter child node information + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [9/12] 0b0a42d54397791f7f149e53c9175b7863707e70 (hreitz/qemu-kvm-c-9-s) + +Before we let qemu-img info print child node information, have +common.filter, common.rc, and iotests.py filter it from the test output +so we get as few reference output changes as possible. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-10-hreitz@redhat.com> +Tested-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit bcc6777ad6facede73c0cf8b1700045bf4365f7d) +Signed-off-by: Hanna Czenczek +--- + tests/qemu-iotests/common.filter | 22 ++++++++++++++-------- + tests/qemu-iotests/common.rc | 22 ++++++++++++++-------- + tests/qemu-iotests/iotests.py | 18 +++++++++++++++--- + 3 files changed, 43 insertions(+), 19 deletions(-) + +diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter +index 6a13757177..6ddda2ee64 100644 +--- a/tests/qemu-iotests/common.filter ++++ b/tests/qemu-iotests/common.filter +@@ -224,6 +224,7 @@ _filter_img_info() + + discard=0 + regex_json_spec_start='^ *"format-specific": \{' ++ regex_json_child_start='^ *"children": \[' + gsed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ + -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ + -e "s#$TEST_DIR#TEST_DIR#g" \ +@@ -252,20 +253,25 @@ _filter_img_info() + -e 's/\(compression type: \)\(zlib\|zstd\)/\1COMPRESSION_TYPE/' \ + -e "s/uuid: [-a-f0-9]\\+/uuid: 00000000-0000-0000-0000-000000000000/" | \ + while IFS='' read -r line; do +- if [[ $format_specific == 1 ]]; then +- discard=0 +- elif [[ $line == "Format specific information:" ]]; then +- discard=1 +- elif [[ $line =~ $regex_json_spec_start ]]; then +- discard=2 +- regex_json_spec_end="^${line%%[^ ]*}\\},? *$" ++ if [[ $discard == 0 ]]; then ++ if [[ $format_specific == 0 && $line == "Format specific information:" ]]; then ++ discard=1 ++ elif [[ $line =~ "Child node '/" ]]; then ++ discard=1 ++ elif [[ $line =~ $regex_json_spec_start ]]; then ++ discard=2 ++ regex_json_end="^${line%%[^ ]*}\\},? *$" ++ elif [[ $line =~ $regex_json_child_start ]]; then ++ discard=2 ++ regex_json_end="^${line%%[^ ]*}\\],? *$" ++ fi + fi + if [[ $discard == 0 ]]; then + echo "$line" + elif [[ $discard == 1 && ! $line ]]; then + echo + discard=0 +- elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then ++ elif [[ $discard == 2 && $line =~ $regex_json_end ]]; then + discard=0 + fi + done +diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc +index db757025cb..f4476b62f7 100644 +--- a/tests/qemu-iotests/common.rc ++++ b/tests/qemu-iotests/common.rc +@@ -711,6 +711,7 @@ _img_info() + + discard=0 + regex_json_spec_start='^ *"format-specific": \{' ++ regex_json_child_start='^ *"children": \[' + $QEMU_IMG info $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1 | \ + sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ + -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ +@@ -721,20 +722,25 @@ _img_info() + -e "/^disk size:/ D" \ + -e "/actual-size/ D" | \ + while IFS='' read -r line; do +- if [[ $format_specific == 1 ]]; then +- discard=0 +- elif [[ $line == "Format specific information:" ]]; then +- discard=1 +- elif [[ $line =~ $regex_json_spec_start ]]; then +- discard=2 +- regex_json_spec_end="^${line%%[^ ]*}\\},? *$" ++ if [[ $discard == 0 ]]; then ++ if [[ $format_specific == 0 && $line == "Format specific information:" ]]; then ++ discard=1 ++ elif [[ $line =~ "Child node '/" ]]; then ++ discard=1 ++ elif [[ $format_specific == 0 && $line =~ $regex_json_spec_start ]]; then ++ discard=2 ++ regex_json_end="^${line%%[^ ]*}\\},? *$" ++ elif [[ $line =~ $regex_json_child_start ]]; then ++ discard=2 ++ regex_json_end="^${line%%[^ ]*}\\],? *$" ++ fi + fi + if [[ $discard == 0 ]]; then + echo "$line" + elif [[ $discard == 1 && ! $line ]]; then + echo + discard=0 +- elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then ++ elif [[ $discard == 2 && $line =~ $regex_json_end ]]; then + discard=0 + fi + done +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index da7d6637e1..94aeb3f3b2 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -329,7 +329,7 @@ def qemu_img_log(*args: str, check: bool = True + + def img_info_log(filename: str, filter_path: Optional[str] = None, + use_image_opts: bool = False, extra_args: Sequence[str] = (), +- check: bool = True, ++ check: bool = True, drop_child_info: bool = True, + ) -> None: + args = ['info'] + if use_image_opts: +@@ -342,7 +342,7 @@ def img_info_log(filename: str, filter_path: Optional[str] = None, + output = qemu_img(*args, check=check).stdout + if not filter_path: + filter_path = filename +- log(filter_img_info(output, filter_path)) ++ log(filter_img_info(output, filter_path, drop_child_info)) + + def qemu_io_wrap_args(args: Sequence[str]) -> List[str]: + if '-f' in args or '--image-opts' in args: +@@ -642,11 +642,23 @@ def _filter(_key, value): + def filter_generated_node_ids(msg): + return re.sub("#block[0-9]+", "NODE_NAME", msg) + +-def filter_img_info(output, filename): ++def filter_img_info(output: str, filename: str, ++ drop_child_info: bool = True) -> str: + lines = [] ++ drop_indented = False + for line in output.split('\n'): + if 'disk size' in line or 'actual-size' in line: + continue ++ ++ # Drop child node info ++ if drop_indented: ++ if line.startswith(' '): ++ continue ++ drop_indented = False ++ if drop_child_info and "Child node '/" in line: ++ drop_indented = True ++ continue ++ + line = line.replace(filename, 'TEST_IMG') + line = filter_testfiles(line) + line = line.replace(imgfmt, 'IMGFMT') +-- +2.31.1 + diff --git a/kvm-qcow2-Fix-theoretical-corruption-in-store_bitmap-err.patch b/kvm-qcow2-Fix-theoretical-corruption-in-store_bitmap-err.patch new file mode 100644 index 0000000..7f39f4a --- /dev/null +++ b/kvm-qcow2-Fix-theoretical-corruption-in-store_bitmap-err.patch @@ -0,0 +1,67 @@ +From 46ead2c391924b68741d6da28f28f909b80f5914 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jan 2023 20:14:51 +0100 +Subject: [PATCH 01/20] qcow2: Fix theoretical corruption in store_bitmap() + error path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Kevin Wolf +RH-MergeRequest: 143: qemu-img: Fix exit code for errors closing the image +RH-Bugzilla: 2150180 +RH-Acked-by: Thomas Huth +RH-Acked-by: Hanna Czenczek +RH-Acked-by: Stefano Garzarella +RH-Commit: [1/4] a6a497947179431567d330d0501247a3749fb9fd (kmwolf/centos-qemu-kvm) + +In order to write the bitmap table to the image file, it is converted to +big endian. If the write fails, it is passed to clear_bitmap_table() to +free all of the clusters it had allocated before. However, if we don't +convert it back to native endianness first, we'll free things at a wrong +offset. + +In practical terms, the offsets will be so high that we won't actually +free any allocated clusters, but just run into an error, but in theory +this can cause image corruption. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Kevin Wolf +Message-Id: <20230112191454.169353-2-kwolf@redhat.com> +Reviewed-by: Hanna Czenczek +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Kevin Wolf +(cherry picked from commit b03dd9613bcf8fe948581b2b3585510cb525c382) +Signed-off-by: Kevin Wolf +--- + block/qcow2-bitmap.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c +index bcad567c0c..3dff99ba06 100644 +--- a/block/qcow2-bitmap.c ++++ b/block/qcow2-bitmap.c +@@ -115,7 +115,7 @@ static int update_header_sync(BlockDriverState *bs) + return bdrv_flush(bs->file->bs); + } + +-static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size) ++static inline void bitmap_table_bswap_be(uint64_t *bitmap_table, size_t size) + { + size_t i; + +@@ -1401,9 +1401,10 @@ static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) + goto fail; + } + +- bitmap_table_to_be(tb, tb_size); ++ bitmap_table_bswap_be(tb, tb_size); + ret = bdrv_pwrite(bs->file, tb_offset, tb_size * sizeof(tb[0]), tb, 0); + if (ret < 0) { ++ bitmap_table_bswap_be(tb, tb_size); + error_setg_errno(errp, -ret, "Failed to write bitmap '%s' to file", + bm_name); + goto fail; +-- +2.31.1 + diff --git a/kvm-qemu-img-Change-info-key-names-for-protocol-nodes.patch b/kvm-qemu-img-Change-info-key-names-for-protocol-nodes.patch new file mode 100644 index 0000000..eff4d2e --- /dev/null +++ b/kvm-qemu-img-Change-info-key-names-for-protocol-nodes.patch @@ -0,0 +1,197 @@ +From b1970c733dc46b2a8f648997a7e1c5d12900ff54 Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:27:04 +0200 +Subject: [PATCH 17/20] qemu-img: Change info key names for protocol nodes + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [12/12] 67c260aaa05466410503fecee6210bf9d47e8c7c (hreitz/qemu-kvm-c-9-s) + +Currently, when querying a qcow2 image, qemu-img info reports something +like this: + +image: test.qcow2 +file format: qcow2 +virtual size: 64 MiB (67108864 bytes) +disk size: 196 KiB +cluster_size: 65536 +Format specific information: + compat: 1.1 + compression type: zlib + lazy refcounts: false + refcount bits: 16 + corrupt: false + extended l2: false +Child node '/file': + image: test.qcow2 + file format: file + virtual size: 192 KiB (197120 bytes) + disk size: 196 KiB + Format specific information: + extent size hint: 1048576 + +Notably, the way the keys are named is specific for image files: The +filename is shown under "image", the BDS driver under "file format", and +the BDS length under "virtual size". This does not make much sense for +nodes that are not actually supposed to be guest images, like the /file +child node shown above. + +Give bdrv_node_info_dump() a @protocol parameter that gives a hint that +the respective node is probably just used for data storage and does not +necessarily present the data for a VM guest disk. This renames the keys +so that with this patch, the output becomes: + +image: test.qcow2 +[...] +Child node '/file': + filename: test.qcow2 + protocol type: file + file length: 192 KiB (197120 bytes) + disk size: 196 KiB + Format specific information: + extent size hint: 1048576 + +(Perhaps we should also rename "Format specific information", but I +could not come up with anything better that will not become problematic +if we guess wrong with the protocol "heuristic".) + +This change affects iotest 302, which has protocol node information in +its reference output. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-13-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit d570177b50c389f379f93183155a27d44856ab46) +Signed-off-by: Hanna Czenczek +--- + block/monitor/block-hmp-cmds.c | 2 +- + block/qapi.c | 39 ++++++++++++++++++++++++++++------ + include/block/qapi.h | 2 +- + qemu-img.c | 3 ++- + tests/qemu-iotests/302.out | 6 +++--- + 5 files changed, 39 insertions(+), 13 deletions(-) + +diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c +index 72824d4e2e..4d83339a5d 100644 +--- a/block/monitor/block-hmp-cmds.c ++++ b/block/monitor/block-hmp-cmds.c +@@ -734,7 +734,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, + monitor_printf(mon, "\nImages:\n"); + image_info = inserted->image; + while (1) { +- bdrv_node_info_dump(qapi_ImageInfo_base(image_info), 0); ++ bdrv_node_info_dump(qapi_ImageInfo_base(image_info), 0, false); + if (image_info->has_backing_image) { + image_info = image_info->backing_image; + } else { +diff --git a/block/qapi.c b/block/qapi.c +index 3e35603f0c..56f398c500 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -934,24 +934,49 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, + visit_free(v); + } + +-void bdrv_node_info_dump(BlockNodeInfo *info, int indentation) ++/** ++ * Print the given @info object in human-readable form. Every field is indented ++ * using the given @indentation (four spaces per indentation level). ++ * ++ * When using this to print a whole block graph, @protocol can be set to true to ++ * signify that the given information is associated with a protocol node, i.e. ++ * just data storage for an image, such that the data it presents is not really ++ * a full VM disk. If so, several fields change name: For example, "virtual ++ * size" is printed as "file length". ++ * (Consider a qcow2 image, which is represented by a qcow2 node and a file ++ * node. Printing a "virtual size" for the file node does not make sense, ++ * because without the qcow2 node, it is not really a guest disk, so it does not ++ * have a "virtual size". Therefore, we call it "file length" instead.) ++ * ++ * @protocol is ignored when @indentation is 0, because we take that to mean ++ * that the associated node is the root node in the queried block graph, and ++ * thus is always to be interpreted as a standalone guest disk. ++ */ ++void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol) + { + char *size_buf, *dsize_buf; + g_autofree char *ind_s = g_strdup_printf("%*s", indentation * 4, ""); + ++ if (indentation == 0) { ++ /* Top level, consider this a normal image */ ++ protocol = false; ++ } ++ + if (!info->has_actual_size) { + dsize_buf = g_strdup("unavailable"); + } else { + dsize_buf = size_to_str(info->actual_size); + } + size_buf = size_to_str(info->virtual_size); +- qemu_printf("%simage: %s\n" +- "%sfile format: %s\n" +- "%svirtual size: %s (%" PRId64 " bytes)\n" ++ qemu_printf("%s%s: %s\n" ++ "%s%s: %s\n" ++ "%s%s: %s (%" PRId64 " bytes)\n" + "%sdisk size: %s\n", +- ind_s, info->filename, +- ind_s, info->format, +- ind_s, size_buf, info->virtual_size, ++ ind_s, protocol ? "filename" : "image", info->filename, ++ ind_s, protocol ? "protocol type" : "file format", ++ info->format, ++ ind_s, protocol ? "file length" : "virtual size", ++ size_buf, info->virtual_size, + ind_s, dsize_buf); + g_free(size_buf); + g_free(dsize_buf); +diff --git a/include/block/qapi.h b/include/block/qapi.h +index 38855f2ae9..26113da21a 100644 +--- a/include/block/qapi.h ++++ b/include/block/qapi.h +@@ -51,5 +51,5 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); + void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, + const char *prefix, + int indentation); +-void bdrv_node_info_dump(BlockNodeInfo *info, int indentation); ++void bdrv_node_info_dump(BlockNodeInfo *info, int indentation, bool protocol); + #endif +diff --git a/qemu-img.c b/qemu-img.c +index e281011245..2943625c67 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2853,7 +2853,8 @@ static void dump_human_image_info(BlockGraphInfo *info, int indentation, + { + BlockChildInfoList *children_list; + +- bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation); ++ bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation, ++ info->children == NULL); + + for (children_list = info->children; children_list; + children_list = children_list->next) +diff --git a/tests/qemu-iotests/302.out b/tests/qemu-iotests/302.out +index edfa1c4f05..7b5014cdd8 100644 +--- a/tests/qemu-iotests/302.out ++++ b/tests/qemu-iotests/302.out +@@ -5,9 +5,9 @@ file format: raw + virtual size: 448 KiB (458752 bytes) + disk size: unavailable + Child node '/file': +- image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock +- file format: nbd +- virtual size: 448 KiB (458752 bytes) ++ filename: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock ++ protocol type: nbd ++ file length: 448 KiB (458752 bytes) + disk size: unavailable + + === Converted image info === +-- +2.31.1 + diff --git a/kvm-qemu-img-Let-info-print-block-graph.patch b/kvm-qemu-img-Let-info-print-block-graph.patch new file mode 100644 index 0000000..536df69 --- /dev/null +++ b/kvm-qemu-img-Let-info-print-block-graph.patch @@ -0,0 +1,261 @@ +From ea73e9de42b446ce1049805c23f7706e4f87ed1f Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:27:03 +0200 +Subject: [PATCH 16/20] qemu-img: Let info print block graph + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [11/12] 2c1b8a03c918484449e876acf4c6663766848ad8 (hreitz/qemu-kvm-c-9-s) + +For every node in the backing chain, collect its BlockGraphInfo struct +using bdrv_query_block_graph_info(). Print all nodes' information, +indenting child nodes and labelling them with a path constructed from +the child names leading to the node from the root (e.g. /file/file). + +Note that we open each image with BDRV_O_NO_BACKING, so its backing +child is omitted from this graph, and thus presented in the previous +manner: By simply concatenating all images' information, separated with +blank lines. + +This affects two iotests: +- 065: Here we try to get the format node's format specific information. + The pre-patch code does so by taking all lines from "Format specific + information:" until an empty line. This format specific information + is no longer followed by an empty line, though, but by child node + information, so limit the range by "Child node '/file':". +- 302: Calls qemu_img() for qemu-img info directly, which does not + filter the output, so the child node information ends up in the + output. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-12-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit c04d0ab026201d21873a63f768cb69c4554dfec1) +Signed-off-by: Hanna Czenczek +--- + qapi/block-core.json | 4 +-- + qemu-img.c | 69 ++++++++++++++++++++++++++------------ + tests/qemu-iotests/065 | 2 +- + tests/qemu-iotests/302.out | 5 +++ + 4 files changed, 56 insertions(+), 24 deletions(-) + +diff --git a/qapi/block-core.json b/qapi/block-core.json +index d703e0fb16..7f331eb8ea 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -5831,9 +5831,9 @@ + ## + # @DummyBlockCoreForceArrays: + # +-# Not used by QMP; hack to let us use BlockNodeInfoList internally ++# Not used by QMP; hack to let us use BlockGraphInfoList internally + # + # Since: 8.0 + ## + { 'struct': 'DummyBlockCoreForceArrays', +- 'data': { 'unused-block-node-info': ['BlockNodeInfo'] } } ++ 'data': { 'unused-block-graph-info': ['BlockGraphInfo'] } } +diff --git a/qemu-img.c b/qemu-img.c +index 30b4ea58bb..e281011245 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2816,13 +2816,13 @@ static void dump_snapshots(BlockDriverState *bs) + g_free(sn_tab); + } + +-static void dump_json_block_node_info_list(BlockNodeInfoList *list) ++static void dump_json_block_graph_info_list(BlockGraphInfoList *list) + { + GString *str; + QObject *obj; + Visitor *v = qobject_output_visitor_new(&obj); + +- visit_type_BlockNodeInfoList(v, NULL, &list, &error_abort); ++ visit_type_BlockGraphInfoList(v, NULL, &list, &error_abort); + visit_complete(v, &obj); + str = qobject_to_json_pretty(obj, true); + assert(str != NULL); +@@ -2832,13 +2832,13 @@ static void dump_json_block_node_info_list(BlockNodeInfoList *list) + g_string_free(str, true); + } + +-static void dump_json_block_node_info(BlockNodeInfo *info) ++static void dump_json_block_graph_info(BlockGraphInfo *info) + { + GString *str; + QObject *obj; + Visitor *v = qobject_output_visitor_new(&obj); + +- visit_type_BlockNodeInfo(v, NULL, &info, &error_abort); ++ visit_type_BlockGraphInfo(v, NULL, &info, &error_abort); + visit_complete(v, &obj); + str = qobject_to_json_pretty(obj, true); + assert(str != NULL); +@@ -2848,9 +2848,29 @@ static void dump_json_block_node_info(BlockNodeInfo *info) + g_string_free(str, true); + } + +-static void dump_human_image_info_list(BlockNodeInfoList *list) ++static void dump_human_image_info(BlockGraphInfo *info, int indentation, ++ const char *path) + { +- BlockNodeInfoList *elem; ++ BlockChildInfoList *children_list; ++ ++ bdrv_node_info_dump(qapi_BlockGraphInfo_base(info), indentation); ++ ++ for (children_list = info->children; children_list; ++ children_list = children_list->next) ++ { ++ BlockChildInfo *child = children_list->value; ++ g_autofree char *child_path = NULL; ++ ++ printf("%*sChild node '%s%s':\n", ++ indentation * 4, "", path, child->name); ++ child_path = g_strdup_printf("%s%s/", path, child->name); ++ dump_human_image_info(child->info, indentation + 1, child_path); ++ } ++} ++ ++static void dump_human_image_info_list(BlockGraphInfoList *list) ++{ ++ BlockGraphInfoList *elem; + bool delim = false; + + for (elem = list; elem; elem = elem->next) { +@@ -2859,7 +2879,7 @@ static void dump_human_image_info_list(BlockNodeInfoList *list) + } + delim = true; + +- bdrv_node_info_dump(elem->value, 0); ++ dump_human_image_info(elem->value, 0, "/"); + } + } + +@@ -2869,7 +2889,7 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) + } + + /** +- * Open an image file chain and return an BlockNodeInfoList ++ * Open an image file chain and return an BlockGraphInfoList + * + * @filename: topmost image filename + * @fmt: topmost image format (may be NULL to autodetect) +@@ -2880,13 +2900,13 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) + * opening an image file. If there was an error a message will have been + * printed to stderr. + */ +-static BlockNodeInfoList *collect_image_info_list(bool image_opts, +- const char *filename, +- const char *fmt, +- bool chain, bool force_share) ++static BlockGraphInfoList *collect_image_info_list(bool image_opts, ++ const char *filename, ++ const char *fmt, ++ bool chain, bool force_share) + { +- BlockNodeInfoList *head = NULL; +- BlockNodeInfoList **tail = &head; ++ BlockGraphInfoList *head = NULL; ++ BlockGraphInfoList **tail = &head; + GHashTable *filenames; + Error *err = NULL; + +@@ -2895,7 +2915,7 @@ static BlockNodeInfoList *collect_image_info_list(bool image_opts, + while (filename) { + BlockBackend *blk; + BlockDriverState *bs; +- BlockNodeInfo *info; ++ BlockGraphInfo *info; + + if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) { + error_report("Backing file '%s' creates an infinite loop.", +@@ -2912,7 +2932,14 @@ static BlockNodeInfoList *collect_image_info_list(bool image_opts, + } + bs = blk_bs(blk); + +- bdrv_query_block_node_info(bs, &info, &err); ++ /* ++ * Note that the returned BlockGraphInfo object will not have ++ * information about this image's backing node, because we have opened ++ * it with BDRV_O_NO_BACKING. Printing this object will therefore not ++ * duplicate the backing chain information that we obtain by walking ++ * the chain manually here. ++ */ ++ bdrv_query_block_graph_info(bs, &info, &err); + if (err) { + error_report_err(err); + blk_unref(blk); +@@ -2945,7 +2972,7 @@ static BlockNodeInfoList *collect_image_info_list(bool image_opts, + return head; + + err: +- qapi_free_BlockNodeInfoList(head); ++ qapi_free_BlockGraphInfoList(head); + g_hash_table_destroy(filenames); + return NULL; + } +@@ -2956,7 +2983,7 @@ static int img_info(int argc, char **argv) + OutputFormat output_format = OFORMAT_HUMAN; + bool chain = false; + const char *filename, *fmt, *output; +- BlockNodeInfoList *list; ++ BlockGraphInfoList *list; + bool image_opts = false; + bool force_share = false; + +@@ -3035,14 +3062,14 @@ static int img_info(int argc, char **argv) + break; + case OFORMAT_JSON: + if (chain) { +- dump_json_block_node_info_list(list); ++ dump_json_block_graph_info_list(list); + } else { +- dump_json_block_node_info(list->value); ++ dump_json_block_graph_info(list->value); + } + break; + } + +- qapi_free_BlockNodeInfoList(list); ++ qapi_free_BlockGraphInfoList(list); + return 0; + } + +diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065 +index b724c89c7c..b76701c71e 100755 +--- a/tests/qemu-iotests/065 ++++ b/tests/qemu-iotests/065 +@@ -56,7 +56,7 @@ class TestQemuImgInfo(TestImageInfoSpecific): + def test_human(self): + data = qemu_img('info', '--output=human', test_img).stdout.split('\n') + data = data[(data.index('Format specific information:') + 1) +- :data.index('')] ++ :data.index("Child node '/file':")] + for field in data: + self.assertTrue(re.match('^ {4}[^ ]', field) is not None) + data = [line.strip() for line in data] +diff --git a/tests/qemu-iotests/302.out b/tests/qemu-iotests/302.out +index 3e7c281b91..edfa1c4f05 100644 +--- a/tests/qemu-iotests/302.out ++++ b/tests/qemu-iotests/302.out +@@ -4,6 +4,11 @@ image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock + file format: raw + virtual size: 448 KiB (458752 bytes) + disk size: unavailable ++Child node '/file': ++ image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock ++ file format: nbd ++ virtual size: 448 KiB (458752 bytes) ++ disk size: unavailable + + === Converted image info === + image: TEST_IMG +-- +2.31.1 + diff --git a/kvm-qemu-img-Use-BlockNodeInfo.patch b/kvm-qemu-img-Use-BlockNodeInfo.patch new file mode 100644 index 0000000..7bfb7e6 --- /dev/null +++ b/kvm-qemu-img-Use-BlockNodeInfo.patch @@ -0,0 +1,241 @@ +From dca4cbe680baff837ca8ac8bd39b77b46af3f64b Mon Sep 17 00:00:00 2001 +From: Hanna Reitz +Date: Mon, 20 Jun 2022 18:26:57 +0200 +Subject: [PATCH 10/20] qemu-img: Use BlockNodeInfo + +RH-Author: Hanna Czenczek +RH-MergeRequest: 145: Show protocol-level information in qemu-img info +RH-Bugzilla: 1860292 +RH-Acked-by: Kevin Wolf +RH-Acked-by: Stefan Hajnoczi +RH-Acked-by: Stefano Garzarella +RH-Commit: [5/12] b599af3ec05951a0ba11d9eae2ee19148d6bf624 (hreitz/qemu-kvm-c-9-s) + +qemu-img info never uses ImageInfo's backing-image field, because it +opens the backing chain one by one with BDRV_O_NO_BACKING, and prints +all backing chain nodes' information consecutively. Use BlockNodeInfo +to make it clear that we only print information about a single node, and +that we are not using the backing-image field. + +Notably, bdrv_image_info_dump() does not evaluate the backing-image +field, so we can easily make it take a BlockNodeInfo pointer (and +consequentially rename it to bdrv_node_info_dump()). It makes more +sense this way, because again, the interface now makes it syntactically +clear that backing-image is ignored by this function. + +Signed-off-by: Hanna Reitz +Message-Id: <20220620162704.80987-6-hreitz@redhat.com> +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit b1f4cd1589a16fec02f264a09bd3560e4ccce3c2) +Signed-off-by: Hanna Czenczek +--- + block/monitor/block-hmp-cmds.c | 2 +- + block/qapi.c | 2 +- + include/block/qapi.h | 2 +- + qapi/block-core.json | 4 +-- + qemu-img.c | 48 +++++++++++++++++----------------- + 5 files changed, 29 insertions(+), 29 deletions(-) + +diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c +index b6135e9bfe..aa37faa601 100644 +--- a/block/monitor/block-hmp-cmds.c ++++ b/block/monitor/block-hmp-cmds.c +@@ -734,7 +734,7 @@ static void print_block_info(Monitor *mon, BlockInfo *info, + monitor_printf(mon, "\nImages:\n"); + image_info = inserted->image; + while (1) { +- bdrv_image_info_dump(image_info); ++ bdrv_node_info_dump(qapi_ImageInfo_base(image_info)); + if (image_info->has_backing_image) { + image_info = image_info->backing_image; + } else { +diff --git a/block/qapi.c b/block/qapi.c +index e5022b4481..ad88bf9b38 100644 +--- a/block/qapi.c ++++ b/block/qapi.c +@@ -865,7 +865,7 @@ void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, + visit_free(v); + } + +-void bdrv_image_info_dump(ImageInfo *info) ++void bdrv_node_info_dump(BlockNodeInfo *info) + { + char *size_buf, *dsize_buf; + if (!info->has_actual_size) { +diff --git a/include/block/qapi.h b/include/block/qapi.h +index c7de4e3fa9..22198dcd0c 100644 +--- a/include/block/qapi.h ++++ b/include/block/qapi.h +@@ -45,5 +45,5 @@ void bdrv_query_image_info(BlockDriverState *bs, + void bdrv_snapshot_dump(QEMUSnapshotInfo *sn); + void bdrv_image_info_specific_dump(ImageInfoSpecific *info_spec, + const char *prefix); +-void bdrv_image_info_dump(ImageInfo *info); ++void bdrv_node_info_dump(BlockNodeInfo *info); + #endif +diff --git a/qapi/block-core.json b/qapi/block-core.json +index 7720da0498..4cf2deeb6c 100644 +--- a/qapi/block-core.json ++++ b/qapi/block-core.json +@@ -5796,9 +5796,9 @@ + ## + # @DummyBlockCoreForceArrays: + # +-# Not used by QMP; hack to let us use ImageInfoList internally ++# Not used by QMP; hack to let us use BlockNodeInfoList internally + # + # Since: 8.0 + ## + { 'struct': 'DummyBlockCoreForceArrays', +- 'data': { 'unused-image-info': ['ImageInfo'] } } ++ 'data': { 'unused-block-node-info': ['BlockNodeInfo'] } } +diff --git a/qemu-img.c b/qemu-img.c +index 2f85bb7ede..3b2ca3bbcb 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2816,13 +2816,13 @@ static void dump_snapshots(BlockDriverState *bs) + g_free(sn_tab); + } + +-static void dump_json_image_info_list(ImageInfoList *list) ++static void dump_json_block_node_info_list(BlockNodeInfoList *list) + { + GString *str; + QObject *obj; + Visitor *v = qobject_output_visitor_new(&obj); + +- visit_type_ImageInfoList(v, NULL, &list, &error_abort); ++ visit_type_BlockNodeInfoList(v, NULL, &list, &error_abort); + visit_complete(v, &obj); + str = qobject_to_json_pretty(obj, true); + assert(str != NULL); +@@ -2832,13 +2832,13 @@ static void dump_json_image_info_list(ImageInfoList *list) + g_string_free(str, true); + } + +-static void dump_json_image_info(ImageInfo *info) ++static void dump_json_block_node_info(BlockNodeInfo *info) + { + GString *str; + QObject *obj; + Visitor *v = qobject_output_visitor_new(&obj); + +- visit_type_ImageInfo(v, NULL, &info, &error_abort); ++ visit_type_BlockNodeInfo(v, NULL, &info, &error_abort); + visit_complete(v, &obj); + str = qobject_to_json_pretty(obj, true); + assert(str != NULL); +@@ -2848,9 +2848,9 @@ static void dump_json_image_info(ImageInfo *info) + g_string_free(str, true); + } + +-static void dump_human_image_info_list(ImageInfoList *list) ++static void dump_human_image_info_list(BlockNodeInfoList *list) + { +- ImageInfoList *elem; ++ BlockNodeInfoList *elem; + bool delim = false; + + for (elem = list; elem; elem = elem->next) { +@@ -2859,7 +2859,7 @@ static void dump_human_image_info_list(ImageInfoList *list) + } + delim = true; + +- bdrv_image_info_dump(elem->value); ++ bdrv_node_info_dump(elem->value); + } + } + +@@ -2869,24 +2869,24 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) + } + + /** +- * Open an image file chain and return an ImageInfoList ++ * Open an image file chain and return an BlockNodeInfoList + * + * @filename: topmost image filename + * @fmt: topmost image format (may be NULL to autodetect) + * @chain: true - enumerate entire backing file chain + * false - only topmost image file + * +- * Returns a list of ImageInfo objects or NULL if there was an error opening an +- * image file. If there was an error a message will have been printed to +- * stderr. ++ * Returns a list of BlockNodeInfo objects or NULL if there was an error ++ * opening an image file. If there was an error a message will have been ++ * printed to stderr. + */ +-static ImageInfoList *collect_image_info_list(bool image_opts, +- const char *filename, +- const char *fmt, +- bool chain, bool force_share) ++static BlockNodeInfoList *collect_image_info_list(bool image_opts, ++ const char *filename, ++ const char *fmt, ++ bool chain, bool force_share) + { +- ImageInfoList *head = NULL; +- ImageInfoList **tail = &head; ++ BlockNodeInfoList *head = NULL; ++ BlockNodeInfoList **tail = &head; + GHashTable *filenames; + Error *err = NULL; + +@@ -2895,7 +2895,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, + while (filename) { + BlockBackend *blk; + BlockDriverState *bs; +- ImageInfo *info; ++ BlockNodeInfo *info; + + if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) { + error_report("Backing file '%s' creates an infinite loop.", +@@ -2912,7 +2912,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, + } + bs = blk_bs(blk); + +- bdrv_query_image_info(bs, &info, &err); ++ bdrv_query_block_node_info(bs, &info, &err); + if (err) { + error_report_err(err); + blk_unref(blk); +@@ -2945,7 +2945,7 @@ static ImageInfoList *collect_image_info_list(bool image_opts, + return head; + + err: +- qapi_free_ImageInfoList(head); ++ qapi_free_BlockNodeInfoList(head); + g_hash_table_destroy(filenames); + return NULL; + } +@@ -2956,7 +2956,7 @@ static int img_info(int argc, char **argv) + OutputFormat output_format = OFORMAT_HUMAN; + bool chain = false; + const char *filename, *fmt, *output; +- ImageInfoList *list; ++ BlockNodeInfoList *list; + bool image_opts = false; + bool force_share = false; + +@@ -3035,14 +3035,14 @@ static int img_info(int argc, char **argv) + break; + case OFORMAT_JSON: + if (chain) { +- dump_json_image_info_list(list); ++ dump_json_block_node_info_list(list); + } else { +- dump_json_image_info(list->value); ++ dump_json_block_node_info(list->value); + } + break; + } + +- qapi_free_ImageInfoList(list); ++ qapi_free_BlockNodeInfoList(list); + return 0; + } + +-- +2.31.1 + diff --git a/kvm-qemu-img-bitmap-Report-errors-while-closing-the-imag.patch b/kvm-qemu-img-bitmap-Report-errors-while-closing-the-imag.patch new file mode 100644 index 0000000..693049c --- /dev/null +++ b/kvm-qemu-img-bitmap-Report-errors-while-closing-the-imag.patch @@ -0,0 +1,70 @@ +From d0d3d694b3a8d200442484ae0c9d263e0439cd04 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jan 2023 20:14:53 +0100 +Subject: [PATCH 03/20] qemu-img bitmap: Report errors while closing the image +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RH-Author: Kevin Wolf +RH-MergeRequest: 143: qemu-img: Fix exit code for errors closing the image +RH-Bugzilla: 2150180 +RH-Acked-by: Thomas Huth +RH-Acked-by: Hanna Czenczek +RH-Acked-by: Stefano Garzarella +RH-Commit: [3/4] 4a704fec2e3bcb47b2be1529e27fd1833d58c517 (kmwolf/centos-qemu-kvm) + +blk_unref() can't report any errors that happen while closing the image. +For example, if qcow2 hits an -ENOSPC error while writing out dirty +bitmaps when it's closed, it prints error messages to stderr, but +'qemu-img bitmap' won't see any error return value and will therefore +look successful with exit code 0. + +In order to fix this, manually inactivate the image first before calling +blk_unref(). This already performs the operations that would be most +likely to fail while closing the image, but it can still return errors. + +Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1330 +Signed-off-by: Kevin Wolf +Message-Id: <20230112191454.169353-4-kwolf@redhat.com> +Reviewed-by: Hanna Czenczek +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Kevin Wolf +(cherry picked from commit c5e477110dcb8ef4642dce399777c3dee68fa96c) +Signed-off-by: Kevin Wolf +--- + qemu-img.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/qemu-img.c b/qemu-img.c +index 3cbdda9f76..2f85bb7ede 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -4646,6 +4646,7 @@ static int img_bitmap(int argc, char **argv) + QSIMPLEQ_HEAD(, ImgBitmapAction) actions; + ImgBitmapAction *act, *act_next; + const char *op; ++ int inactivate_ret; + + QSIMPLEQ_INIT(&actions); + +@@ -4830,6 +4831,16 @@ static int img_bitmap(int argc, char **argv) + ret = 0; + + out: ++ /* ++ * Manually inactivate the images first because this way we can know whether ++ * an error occurred. blk_unref() doesn't tell us about failures. ++ */ ++ inactivate_ret = bdrv_inactivate_all(); ++ if (inactivate_ret < 0) { ++ error_report("Error while closing the image: %s", strerror(-inactivate_ret)); ++ ret = 1; ++ } ++ + blk_unref(src); + blk_unref(blk); + qemu_opts_del(opts); +-- +2.31.1 + diff --git a/kvm-qemu-img-commit-Report-errors-while-closing-the-imag.patch b/kvm-qemu-img-commit-Report-errors-while-closing-the-imag.patch new file mode 100644 index 0000000..5cac3ba --- /dev/null +++ b/kvm-qemu-img-commit-Report-errors-while-closing-the-imag.patch @@ -0,0 +1,67 @@ +From 2f5369f0effaa23be746f9b5d9f6a0bfc346fb7d Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jan 2023 20:14:52 +0100 +Subject: [PATCH 02/20] qemu-img commit: Report errors while closing the image + +RH-Author: Kevin Wolf +RH-MergeRequest: 143: qemu-img: Fix exit code for errors closing the image +RH-Bugzilla: 2150180 +RH-Acked-by: Thomas Huth +RH-Acked-by: Hanna Czenczek +RH-Acked-by: Stefano Garzarella +RH-Commit: [2/4] faedd43355463b1210a3f21ecd430f478bd06f5a (kmwolf/centos-qemu-kvm) + +blk_unref() can't report any errors that happen while closing the image. +For example, if qcow2 hits an -ENOSPC error while writing out dirty +bitmaps when it's closed, it prints error messages to stderr, but +'qemu-img commit' won't see any error return value and will therefore +look successful with exit code 0. + +In order to fix this, manually inactivate the image first before calling +blk_unref(). This already performs the operations that would be most +likely to fail while closing the image, but it can still return errors. + +Signed-off-by: Kevin Wolf +Message-Id: <20230112191454.169353-3-kwolf@redhat.com> +Reviewed-by: Hanna Czenczek +Signed-off-by: Kevin Wolf +(cherry picked from commit 44efba2d713aca076c411594d0c1a2b99155eeb3) +Signed-off-by: Kevin Wolf +--- + qemu-img.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/qemu-img.c b/qemu-img.c +index a9b3a8103c..3cbdda9f76 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -449,6 +449,11 @@ static BlockBackend *img_open(bool image_opts, + blk = img_open_file(filename, NULL, fmt, flags, writethrough, quiet, + force_share); + } ++ ++ if (blk) { ++ blk_set_force_allow_inactivate(blk); ++ } ++ + return blk; + } + +@@ -1119,6 +1124,14 @@ unref_backing: + done: + qemu_progress_end(); + ++ /* ++ * Manually inactivate the image first because this way we can know whether ++ * an error occurred. blk_unref() doesn't tell us about failures. ++ */ ++ ret = bdrv_inactivate_all(); ++ if (ret < 0 && !local_err) { ++ error_setg_errno(&local_err, -ret, "Error while closing the image"); ++ } + blk_unref(blk); + + if (local_err) { +-- +2.31.1 + diff --git a/kvm-qemu-iotests-Test-qemu-img-bitmap-commit-exit-code-o.patch b/kvm-qemu-iotests-Test-qemu-img-bitmap-commit-exit-code-o.patch new file mode 100644 index 0000000..6b88e5c --- /dev/null +++ b/kvm-qemu-iotests-Test-qemu-img-bitmap-commit-exit-code-o.patch @@ -0,0 +1,166 @@ +From 06030aa79fcb2d90d6a670e75d959aa0c3204b5c Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Thu, 12 Jan 2023 20:14:54 +0100 +Subject: [PATCH 04/20] qemu-iotests: Test qemu-img bitmap/commit exit code on + error + +RH-Author: Kevin Wolf +RH-MergeRequest: 143: qemu-img: Fix exit code for errors closing the image +RH-Bugzilla: 2150180 +RH-Acked-by: Thomas Huth +RH-Acked-by: Hanna Czenczek +RH-Acked-by: Stefano Garzarella +RH-Commit: [4/4] b96bb671bcfb7ae18015fda14db70f42a83a6ea7 (kmwolf/centos-qemu-kvm) + +This tests that when an error happens while writing back bitmaps to the +image file in qcow2_inactivate(), 'qemu-img bitmap/commit' actually +return an error value in their exit code instead of making the operation +look successful to scripts. + +Signed-off-by: Kevin Wolf +Message-Id: <20230112191454.169353-5-kwolf@redhat.com> +Reviewed-by: Hanna Czenczek +Signed-off-by: Kevin Wolf +(cherry picked from commit 07a4e1f8e5418f36424cd57d5d061b090a238c65) +Signed-off-by: Kevin Wolf +--- + .../qemu-iotests/tests/qemu-img-close-errors | 96 +++++++++++++++++++ + .../tests/qemu-img-close-errors.out | 23 +++++ + 2 files changed, 119 insertions(+) + create mode 100755 tests/qemu-iotests/tests/qemu-img-close-errors + create mode 100644 tests/qemu-iotests/tests/qemu-img-close-errors.out + +diff --git a/tests/qemu-iotests/tests/qemu-img-close-errors b/tests/qemu-iotests/tests/qemu-img-close-errors +new file mode 100755 +index 0000000000..50bfb6cfa2 +--- /dev/null ++++ b/tests/qemu-iotests/tests/qemu-img-close-errors +@@ -0,0 +1,96 @@ ++#!/usr/bin/env bash ++# group: rw auto quick ++# ++# Check that errors while closing the image, in particular writing back dirty ++# bitmaps, is correctly reported with a failing qemu-img exit code. ++# ++# Copyright (C) 2023 Red Hat, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# creator ++owner=kwolf@redhat.com ++ ++seq="$(basename $0)" ++echo "QA output created by $seq" ++ ++status=1 # failure is the default! ++ ++_cleanup() ++{ ++ _cleanup_test_img ++} ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# get standard environment, filters and checks ++cd .. ++. ./common.rc ++. ./common.filter ++ ++_supported_fmt qcow2 ++_supported_proto file ++_supported_os Linux ++ ++size=1G ++ ++# The error we are going to use is ENOSPC. Depending on how many bitmaps we ++# create in the backing file (and therefore increase the used up space), we get ++# failures in different places. With a low number, only merging the bitmap ++# fails, whereas with a higher number, already 'qemu-img commit' fails. ++for max_bitmap in 6 7; do ++ echo ++ echo "=== Test with $max_bitmap bitmaps ===" ++ ++ TEST_IMG="$TEST_IMG.base" _make_test_img -q $size ++ for i in $(seq 1 $max_bitmap); do ++ $QEMU_IMG bitmap --add "$TEST_IMG.base" "stale-bitmap-$i" ++ done ++ ++ # Simulate a block device of 128 MB by resizing the image file accordingly ++ # and then enforcing the size with the raw driver ++ $QEMU_IO -f raw -c "truncate 128M" "$TEST_IMG.base" ++ BASE_JSON='json:{ ++ "driver": "qcow2", ++ "file": { ++ "driver": "raw", ++ "size": 134217728, ++ "file": { ++ "driver": "file", ++ "filename":"'"$TEST_IMG.base"'" ++ } ++ } ++ }' ++ ++ _make_test_img -q -b "$BASE_JSON" -F $IMGFMT ++ $QEMU_IMG bitmap --add "$TEST_IMG" "good-bitmap" ++ ++ $QEMU_IO -c 'write 0 126m' "$TEST_IMG" | _filter_qemu_io ++ ++ $QEMU_IMG commit -d "$TEST_IMG" 2>&1 | _filter_generated_node_ids ++ echo "qemu-img commit exit code: ${PIPESTATUS[0]}" ++ ++ $QEMU_IMG bitmap --add "$BASE_JSON" "good-bitmap" ++ echo "qemu-img bitmap --add exit code: $?" ++ ++ $QEMU_IMG bitmap --merge "good-bitmap" -b "$TEST_IMG" "$BASE_JSON" \ ++ "good-bitmap" 2>&1 | _filter_generated_node_ids ++ echo "qemu-img bitmap --merge exit code: ${PIPESTATUS[0]}" ++done ++ ++# success, all done ++echo "*** done" ++rm -f $seq.full ++status=0 ++ +diff --git a/tests/qemu-iotests/tests/qemu-img-close-errors.out b/tests/qemu-iotests/tests/qemu-img-close-errors.out +new file mode 100644 +index 0000000000..1bfe88f176 +--- /dev/null ++++ b/tests/qemu-iotests/tests/qemu-img-close-errors.out +@@ -0,0 +1,23 @@ ++QA output created by qemu-img-close-errors ++ ++=== Test with 6 bitmaps === ++wrote 132120576/132120576 bytes at offset 0 ++126 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++Image committed. ++qemu-img commit exit code: 0 ++qemu-img bitmap --add exit code: 0 ++qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'good-bitmap' to file: No space left on device ++qemu-img: Error while closing the image: Invalid argument ++qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'good-bitmap' to file: No space left on device ++qemu-img bitmap --merge exit code: 1 ++ ++=== Test with 7 bitmaps === ++wrote 132120576/132120576 bytes at offset 0 ++126 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'stale-bitmap-7' to file: No space left on device ++qemu-img: Lost persistent bitmaps during inactivation of node 'NODE_NAME': Failed to write bitmap 'stale-bitmap-7' to file: No space left on device ++qemu-img: Error while closing the image: Invalid argument ++qemu-img commit exit code: 1 ++qemu-img bitmap --add exit code: 0 ++qemu-img bitmap --merge exit code: 0 ++*** done +-- +2.31.1 + diff --git a/kvm-virtio-rng-pci-fix-transitional-migration-compat-for.patch b/kvm-virtio-rng-pci-fix-transitional-migration-compat-for.patch new file mode 100644 index 0000000..e5288d6 --- /dev/null +++ b/kvm-virtio-rng-pci-fix-transitional-migration-compat-for.patch @@ -0,0 +1,47 @@ +From 5413b8825db6eecc6f245854a6bce58e4dee3294 Mon Sep 17 00:00:00 2001 +From: "Dr. David Alan Gilbert" +Date: Tue, 7 Feb 2023 17:57:39 +0000 +Subject: [PATCH 20/20] virtio-rng-pci: fix transitional migration compat for + vectors + +RH-Author: Dr. David Alan Gilbert +RH-MergeRequest: 147: virtio-rng-pci: fix transitional migration compat for vectors +RH-Bugzilla: 2162569 +RH-Acked-by: Miroslav Rezanina +RH-Acked-by: Thomas Huth +RH-Acked-by: Gerd Hoffmann +RH-Commit: [1/1] 6e2bd111cd56808fccf2c0464a40f7784fd893a2 (dagrh/c-9-s-qemu-kvm) + +In upstream bad9c5a5166/downstream 46e08bafe9ed I fixed the virito-rng-pci +migration compatibility, but it was discovered that we also need to fix +the other aliases of the device for the transitional cases. + +I've sent upstream: +https://lists.gnu.org/archive/html/qemu-devel/2023-02/msg01926.html +but downstream we need to change the downstream machine type anyway, +so it's not quite identical. + +Fixes: 9ea02e8f1 ('virtio-rng-pci: Allow setting nvectors, so we can use MSI-X') + +Signed-off-by: Dr. David Alan Gilbert +--- + hw/core/machine.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/core/machine.c b/hw/core/machine.c +index 7adbac6f87..3ee638394b 100644 +--- a/hw/core/machine.c ++++ b/hw/core/machine.c +@@ -58,6 +58,9 @@ GlobalProperty hw_compat_rhel_9_1[] = { + { "virtio-device", "queue_reset", "false" }, + /* hw_compat_rhel_9_1 bz 2155749 */ + { "virtio-rng-pci", "vectors", "0" }, ++ /* hw_compat_rhel_9_1 bz 2162569 */ ++ { "virtio-rng-pci-transitional", "vectors", "0" }, ++ { "virtio-rng-pci-non-transitional", "vectors", "0" }, + }; + const size_t hw_compat_rhel_9_1_len = G_N_ELEMENTS(hw_compat_rhel_9_1); + +-- +2.31.1 + diff --git a/qemu-kvm.spec b/qemu-kvm.spec index 6dedf40..a9baa8e 100644 --- a/qemu-kvm.spec +++ b/qemu-kvm.spec @@ -148,7 +148,7 @@ Obsoletes: %{name}-block-ssh <= %{epoch}:%{version} \ Summary: QEMU is a machine emulator and virtualizer Name: qemu-kvm Version: 7.2.0 -Release: 7%{?rcrel}%{?dist}%{?cc_suffix} +Release: 8%{?rcrel}%{?dist}%{?cc_suffix} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped # Epoch 15 used for RHEL 8 # Epoch 17 used for RHEL 9 (due to release versioning offset in RHEL 8.5) @@ -316,6 +316,46 @@ Patch83: kvm-vdpa-add-shadow_data-to-vhost_vdpa.patch Patch84: kvm-vdpa-always-start-CVQ-in-SVQ-mode-if-possible.patch # For bz#2104412 - vDPA ASID support in Qemu Patch85: kvm-vdpa-fix-VHOST_BACKEND_F_IOTLB_ASID-flag-check.patch +# For bz#2150180 - qemu-img finishes successfully while having errors in commit or bitmaps operations +Patch86: kvm-qcow2-Fix-theoretical-corruption-in-store_bitmap-err.patch +# For bz#2150180 - qemu-img finishes successfully while having errors in commit or bitmaps operations +Patch87: kvm-qemu-img-commit-Report-errors-while-closing-the-imag.patch +# For bz#2150180 - qemu-img finishes successfully while having errors in commit or bitmaps operations +Patch88: kvm-qemu-img-bitmap-Report-errors-while-closing-the-imag.patch +# For bz#2150180 - qemu-img finishes successfully while having errors in commit or bitmaps operations +Patch89: kvm-qemu-iotests-Test-qemu-img-bitmap-commit-exit-code-o.patch +# For bz#2165280 - [kvm-unit-tests] debug-wp-migration fails +Patch90: kvm-accel-tcg-Test-CPUJumpCache-in-tb_jmp_cache_clear_pa.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch91: kvm-block-Improve-empty-format-specific-info-dump.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch92: kvm-block-file-Add-file-specific-image-info.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch93: kvm-block-vmdk-Change-extent-info-type.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch94: kvm-block-Split-BlockNodeInfo-off-of-ImageInfo.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch95: kvm-qemu-img-Use-BlockNodeInfo.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch96: kvm-block-qapi-Let-bdrv_query_image_info-recurse.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch97: kvm-block-qapi-Introduce-BlockGraphInfo.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch98: kvm-block-qapi-Add-indentation-to-bdrv_node_info_dump.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch99: kvm-iotests-Filter-child-node-information.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch100: kvm-iotests-106-214-308-Read-only-one-size-line.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch101: kvm-qemu-img-Let-info-print-block-graph.patch +# For bz#1860292 - RFE: add extent_size_hint information to qemu-img info +Patch102: kvm-qemu-img-Change-info-key-names-for-protocol-nodes.patch +# For bz#2155173 - [vhost-user] unable to start vhost net: 71: falling back on userspace +Patch103: kvm-Revert-vhost-user-Monitor-slave-channel-in-vhost_use.patch +# For bz#2155173 - [vhost-user] unable to start vhost net: 71: falling back on userspace +Patch104: kvm-Revert-vhost-user-Introduce-nested-event-loop-in-vho.patch +# For bz#2162569 - [transitional device][virtio-rng-pci-transitional]Stable Guest ABI failed between RHEL 8.6 to RHEL 9.2 +Patch105: kvm-virtio-rng-pci-fix-transitional-migration-compat-for.patch %if %{have_clang} BuildRequires: clang @@ -1346,6 +1386,38 @@ useradd -r -u 107 -g qemu -G kvm -d / -s /sbin/nologin \ %endif %changelog +* Thu Feb 09 2023 Miroslav Rezanina - 7.2.0-8 +- kvm-qcow2-Fix-theoretical-corruption-in-store_bitmap-err.patch [bz#2150180] +- kvm-qemu-img-commit-Report-errors-while-closing-the-imag.patch [bz#2150180] +- kvm-qemu-img-bitmap-Report-errors-while-closing-the-imag.patch [bz#2150180] +- kvm-qemu-iotests-Test-qemu-img-bitmap-commit-exit-code-o.patch [bz#2150180] +- kvm-accel-tcg-Test-CPUJumpCache-in-tb_jmp_cache_clear_pa.patch [bz#2165280] +- kvm-block-Improve-empty-format-specific-info-dump.patch [bz#1860292] +- kvm-block-file-Add-file-specific-image-info.patch [bz#1860292] +- kvm-block-vmdk-Change-extent-info-type.patch [bz#1860292] +- kvm-block-Split-BlockNodeInfo-off-of-ImageInfo.patch [bz#1860292] +- kvm-qemu-img-Use-BlockNodeInfo.patch [bz#1860292] +- kvm-block-qapi-Let-bdrv_query_image_info-recurse.patch [bz#1860292] +- kvm-block-qapi-Introduce-BlockGraphInfo.patch [bz#1860292] +- kvm-block-qapi-Add-indentation-to-bdrv_node_info_dump.patch [bz#1860292] +- kvm-iotests-Filter-child-node-information.patch [bz#1860292] +- kvm-iotests-106-214-308-Read-only-one-size-line.patch [bz#1860292] +- kvm-qemu-img-Let-info-print-block-graph.patch [bz#1860292] +- kvm-qemu-img-Change-info-key-names-for-protocol-nodes.patch [bz#1860292] +- kvm-Revert-vhost-user-Monitor-slave-channel-in-vhost_use.patch [bz#2155173] +- kvm-Revert-vhost-user-Introduce-nested-event-loop-in-vho.patch [bz#2155173] +- kvm-virtio-rng-pci-fix-transitional-migration-compat-for.patch [bz#2162569] +- Resolves: bz#2150180 + (qemu-img finishes successfully while having errors in commit or bitmaps operations) +- Resolves: bz#2165280 + ([kvm-unit-tests] debug-wp-migration fails) +- Resolves: bz#1860292 + (RFE: add extent_size_hint information to qemu-img info) +- Resolves: bz#2155173 + ([vhost-user] unable to start vhost net: 71: falling back on userspace) +- Resolves: bz#2162569 + ([transitional device][virtio-rng-pci-transitional]Stable Guest ABI failed between RHEL 8.6 to RHEL 9.2) + * Mon Feb 06 2023 Miroslav Rezanina - 7.2.0-7 - kvm-vdpa-use-v-shadow_vqs_enabled-in-vhost_vdpa_svqs_sta.patch [bz#2104412] - kvm-vhost-set-SVQ-device-call-handler-at-SVQ-start.patch [bz#2104412]