From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 399731FF0B3 for ; Wed, 14 Oct 2026 15:57:54 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 0A8D621432; Wed, 14 Oct 2026 15:57:50 +0200 (CEST) From: Fiona Ebner To: pve-devel@lists.proxmox.com Subject: [PATCH qemu v2 2/2] more stable fixes for QEMU 11.1 Date: Tue, 13 Oct 2026 10:38:59 +0200 Message-ID: <20261013083919.48588-3-f.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261013083919.48588-1-f.ebner@proxmox.com> References: <20261013083919.48588-1-f.ebner@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1791880763649 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.311 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) KAM_LOTSOFHASH 0.25 Emails with lots of hash-like gibberish RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record X-MailFrom: f.ebner@proxmox.com X-Mailman-Rule-Hits: max-size X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; news-moderation; no-subject; digests; suspicious-header Message-ID-Hash: INE2BWTLYWBEA7UXXEINPVIPUUD6FQDN X-Message-ID-Hash: INE2BWTLYWBEA7UXXEINPVIPUUD6FQDN X-Mailman-Approved-At: Wed, 14 Oct 2026 15:57:16 +0200 X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Pick up a corruption fix for the block layer, a fix to avoid a crash for querying VirtIO information via QMP/HMP, fixes to improve flush error reporting upon close and for qemu-img, a fix for iterating block nodes, and hardenings for KVM and USB emulation. Signed-off-by: Fiona Ebner --- Changes in v2: * Pick up fix for crash when querying info for VirtIO via QMP/HMP. * Pick up hardendings for KVM and a fix for TDX. ...-Limit-DMA-transfers-to-plain-memory.patch | 85 ++ ...corruption-from-broken-RMW-atomicity.patch | 124 +++ ...-redundant-bdrv_wait_serialising_req.patch | 71 ++ ...rv_next-skipping-monitor-owned-nodes.patch | 118 +++ ...-cases-for-failing-flush-after-qemu-.patch | 88 ++ .../0010-iotests.py-add-filter_qemu.patch | 34 + ...report-flush-error-during-bdrv_close.patch | 763 ++++++++++++++++++ ...ert-flush-target-image-after-copying.patch | 99 +++ ...ore-backend-features-in-x-query-virt.patch | 41 + ...dle-missing-vhost-user-protocol-feat.patch | 74 ++ ...r-overflow-in-tdx_parse_panic_messag.patch | 100 +++ ...ct-kvm_resample_fd_list-with-a-mutex.patch | 134 +++ ...ced-mmio-check-lenght-of-the-MMIO-wr.patch | 55 ++ ...return-success-on-info-without-snaps.patch | 4 +- ...dd-add-osize-and-read-from-to-stdin-.patch | 12 +- ...E-Up-qemu-img-dd-add-isize-parameter.patch | 14 +- ...PVE-Up-qemu-img-dd-add-n-skip_create.patch | 10 +- ...-add-l-option-for-loading-a-snapshot.patch | 14 +- ...-Backup-add-backup-dump-block-driver.patch | 2 +- ...ment-backup-access-setup-and-teardow.patch | 6 +- debian/patches/series | 13 + 21 files changed, 1830 insertions(+), 31 deletions(-) create mode 100644 debian/patches/extra/0005-hw-usb-hcd-xhci-Limit-DMA-transfers-to-plain-memory.patch create mode 100644 debian/patches/extra/0006-block-Fix-corruption-from-broken-RMW-atomicity.patch create mode 100644 debian/patches/extra/0007-block-Remove-now-redundant-bdrv_wait_serialising_req.patch create mode 100644 debian/patches/extra/0008-block-fix-bdrv_next-skipping-monitor-owned-nodes.patch create mode 100644 debian/patches/extra/0009-iotests-add-test-cases-for-failing-flush-after-qemu-.patch create mode 100644 debian/patches/extra/0010-iotests.py-add-filter_qemu.patch create mode 100644 debian/patches/extra/0011-block-report-flush-error-during-bdrv_close.patch create mode 100644 debian/patches/extra/0012-qemu-img-convert-flush-target-image-after-copying.patch create mode 100644 debian/patches/extra/0013-qapi-virtio-Restore-backend-features-in-x-query-virt.patch create mode 100644 debian/patches/extra/0014-qapi-monitor-Handle-missing-vhost-user-protocol-feat.patch create mode 100644 debian/patches/extra/0015-system-fix-buffer-overflow-in-tdx_parse_panic_messag.patch create mode 100644 debian/patches/extra/0016-accel-kvm-protect-kvm_resample_fd_list-with-a-mutex.patch create mode 100644 debian/patches/extra/0017-accel-kvm-coalesced-mmio-check-lenght-of-the-MMIO-wr.patch diff --git a/debian/patches/extra/0005-hw-usb-hcd-xhci-Limit-DMA-transfers-to-plain-memory.patch b/debian/patches/extra/0005-hw-usb-hcd-xhci-Limit-DMA-transfers-to-plain-memory.patch new file mode 100644 index 0000000000..d30c86d8b2 --- /dev/null +++ b/debian/patches/extra/0005-hw-usb-hcd-xhci-Limit-DMA-transfers-to-plain-memory.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Thomas Huth +Date: Tue, 15 Sep 2026 14:32:42 +0200 +Subject: [PATCH] hw/usb/hcd-xhci: Limit DMA transfers to plain memory + +XHCI is a complex controller, involving lots of descriptors that +are written and read via DMA transfers. As some recent bugs like +https://gitlab.com/qemu-project/qemu/-/work_items/3926 revealed, +this can sometimes be exploited from the guest side to crash or +stall QEMU. + +The code currently does DMA writes with the MEMTXATTRS_UNSPECIFIED +attribute, i.e. the controller is allowed to write to other MMIO +regions, too. However, in normal operation, this should not be +necessary, all descriptors should reside in normal memory. So let's +decrease the attack surface a little bit and limit the DMA writes +to normal memory here. + +Signed-off-by: Thomas Huth +Message-ID: <20260915123242.549150-1-thuth@redhat.com> +(cherry picked from commit 89e653b77369ad2d3e579139b1fa2567daa86a79) +Signed-off-by: Fiona Ebner +--- + hw/usb/hcd-xhci.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 624ce4ee75..376bc00264 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -518,6 +518,7 @@ static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr, + int i; + uint32_t tmp[5]; + uint32_t n = len / sizeof(uint32_t); ++ const MemTxAttrs memtx_attrs = { .memory = true }; + + assert((len % sizeof(uint32_t)) == 0); + assert(n <= ARRAY_SIZE(tmp)); +@@ -525,8 +526,7 @@ static inline void xhci_dma_write_u32s(XHCIState *xhci, dma_addr_t addr, + for (i = 0; i < n; i++) { + tmp[i] = cpu_to_le32(buf[i]); + } +- if (dma_memory_write(xhci->as, addr, tmp, len, +- MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { ++ if (dma_memory_write(xhci->as, addr, tmp, len, memtx_attrs) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n", + __func__); + xhci_die(xhci); +@@ -613,6 +613,7 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) + XHCIInterrupter *intr = &xhci->intr[v]; + XHCITRB ev_trb; + dma_addr_t addr; ++ const MemTxAttrs memtx_attrs = { .memory = true }; + + ev_trb.parameter = cpu_to_le64(event->ptr); + ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24)); +@@ -629,7 +630,7 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) + + addr = intr->er_start + TRB_SIZE*intr->er_ep_idx; + if (dma_memory_write(xhci->as, addr, &ev_trb, TRB_SIZE, +- MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { ++ memtx_attrs) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n", + __func__); + xhci_die(xhci); +@@ -2440,6 +2441,7 @@ static void xhci_detach_slot(XHCIState *xhci, USBPort *uport) + static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) + { + dma_addr_t ctx; ++ const MemTxAttrs memtx_attrs = { .memory = true }; + + DPRINTF("xhci_get_port_bandwidth()\n"); + +@@ -2448,9 +2450,9 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) + DPRINTF("xhci: bandwidth context at "DMA_ADDR_FMT"\n", ctx); + + /* TODO: actually implement real values here. This is 80% for all ports. */ +- if (stb_dma(xhci->as, ctx, 0, MEMTXATTRS_UNSPECIFIED) != MEMTX_OK || ++ if (stb_dma(xhci->as, ctx, 0, memtx_attrs) != MEMTX_OK || + dma_memory_set(xhci->as, ctx + 1, 80, xhci->numports, +- MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) { ++ memtx_attrs) != MEMTX_OK) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory write failed!\n", + __func__); + return CC_TRB_ERROR; diff --git a/debian/patches/extra/0006-block-Fix-corruption-from-broken-RMW-atomicity.patch b/debian/patches/extra/0006-block-Fix-corruption-from-broken-RMW-atomicity.patch new file mode 100644 index 0000000000..d34d79bb26 --- /dev/null +++ b/debian/patches/extra/0006-block-Fix-corruption-from-broken-RMW-atomicity.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 2 Oct 2026 15:21:34 +0200 +Subject: [PATCH] block: Fix corruption from broken RMW atomicity + +When emulating 512 byte sector devices on top of 4k native host storage, +QEMU performs a read-modify-write cycle for misaligned write requests. +These requests are marked as serialising so that any other writes to the +same 4k block will have to wait and can't overwrite the block in the +middle, which would make the RMW write back stale data. + +In principle, this mechanism works fine, but there is a race condition +in the implementation: bdrv_find_conflicting_request() assumes that +req->waiting_for == NULL means that the request is the active owner of +the data blocks it touches and everyone else has to wait for this +request. However, there is a window between tracked_request_begin() and +bdrv_wait_serialising_requests_locked() where any new request has +req->waiting_for == NULL even if it conflicts with an already running +serialising request. So at this point, we have seemingly two active +owners at the same time until the new request checks for conflicts. + +For a third request coming in, this isn't a problem, it just might wait +for a little longer than necessary. However, if the original RMW request +calls bdrv_wait_serialising_requests_locked() again (which it does in +bdrv_aligned_pwritev() -> bdrv_co_write_req_prepare() before writing +back the RMW buffer), it will now wait on the other request that snuck +in, which is fatal and makes the RMW buffer stale. This scenario causes +data corruption. + +Fix this by checking for conflicts already in tracked_request_begin() +while holding the bs->reqs_lock mutex, so that the race window is closed +and req->waiting_for == NULL really has the intended meaning. + +For good measure, add an active_owner boolean that is set when a request +is marked serialising and has completed waiting for other requests, and +assert that it is not set when waiting for another request, so that in +the case of another bug, we'd crash instead of causing data corruption. + +Cc: qemu-stable@nongnu.org +Buglink: https://redhat.atlassian.net/browse/RHEL-272836 +Signed-off-by: Kevin Wolf +Message-ID: <20261002132135.93345-2-kwolf@redhat.com> +Signed-off-by: Kevin Wolf +(cherry picked from commit 0bd5a1b3d60cca595e19bb73eec83307259be671) +Signed-off-by: Fiona Ebner +--- + block/io.c | 23 +++++++++++++++++++++++ + include/block/block_int-common.h | 1 + + 2 files changed, 24 insertions(+) + +diff --git a/block/io.c b/block/io.c +index a916b236c3..bd562d472f 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -50,6 +50,9 @@ + static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, + int64_t offset, int64_t bytes, BdrvRequestFlags flags); + ++static void coroutine_fn ++bdrv_wait_serialising_requests_locked(BdrvTrackedRequest *self); ++ + static void GRAPH_RDLOCK + bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) + { +@@ -616,6 +619,7 @@ static void coroutine_fn tracked_request_begin(BdrvTrackedRequest *req, + .type = type, + .co = qemu_coroutine_self(), + .serialising = false, ++ .active_owner = false, + .overlap_offset = offset, + .overlap_bytes = bytes, + }; +@@ -624,6 +628,15 @@ static void coroutine_fn tracked_request_begin(BdrvTrackedRequest *req, + + qemu_mutex_lock(&bs->reqs_lock); + QLIST_INSERT_HEAD(&bs->tracked_requests, req, list); ++ ++ /* ++ * Set .waiting_for while we're holding the lock, otherwise we'd open a race ++ * window where another request in the middle of its RMW cycle starts ++ * waiting for us, leading to potential data corruption if this request ++ * overwrites a block the RMW request has already read. ++ */ ++ bdrv_wait_serialising_requests_locked(req); ++ + qemu_mutex_unlock(&bs->reqs_lock); + } + +@@ -684,6 +697,15 @@ bdrv_wait_serialising_requests_locked(BdrvTrackedRequest *self) + BdrvTrackedRequest *req; + + while ((req = bdrv_find_conflicting_request(self))) { ++ /* ++ * If this request is the active owner of the data blocks it accesses, ++ * no other conflicting request may exist; other requests have to wait ++ * for this one, not the other way around. If this condition is ++ * violated, RMW operations may be interrupted in the middle, operate on ++ * stale data and introduce data corruption. ++ */ ++ assert(!self->active_owner); ++ + self->waiting_for = req; + qemu_co_queue_wait(&req->wait_queue, &self->bs->reqs_lock); + self->waiting_for = NULL; +@@ -803,6 +825,7 @@ void coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, + + tracked_request_set_serialising(req, align); + bdrv_wait_serialising_requests_locked(req); ++ req->active_owner = true; + + qemu_mutex_unlock(&req->bs->reqs_lock); + } +diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h +index 147c08155f..46428b034d 100644 +--- a/include/block/block_int-common.h ++++ b/include/block/block_int-common.h +@@ -80,6 +80,7 @@ typedef struct BdrvTrackedRequest { + enum BdrvTrackedRequestType type; + + bool serialising; ++ bool active_owner; + int64_t overlap_offset; + int64_t overlap_bytes; + diff --git a/debian/patches/extra/0007-block-Remove-now-redundant-bdrv_wait_serialising_req.patch b/debian/patches/extra/0007-block-Remove-now-redundant-bdrv_wait_serialising_req.patch new file mode 100644 index 0000000000..c85c3beac5 --- /dev/null +++ b/debian/patches/extra/0007-block-Remove-now-redundant-bdrv_wait_serialising_req.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kevin Wolf +Date: Fri, 2 Oct 2026 15:21:35 +0200 +Subject: [PATCH] block: Remove now redundant bdrv_wait_serialising_requests() + calls + +All callers of bdrv_wait_serialising_requests() (as opposed to +bdrv_wait_serialising_requests_locked()) are just duplicating the check +that tracked_request_begin() already performs now. After removing them, +bdrv_wait_serialising_requests() has no callers left and can go as well. + +Signed-off-by: Kevin Wolf +Message-ID: <20261002132135.93345-3-kwolf@redhat.com> +Signed-off-by: Kevin Wolf +(cherry picked from commit cf4f672c11d663f87462cfd99a92124b30804e99) +Signed-off-by: Fiona Ebner +--- + block/io.c | 19 ------------------- + 1 file changed, 19 deletions(-) + +diff --git a/block/io.c b/block/io.c +index bd562d472f..1c05dd106d 100644 +--- a/block/io.c ++++ b/block/io.c +@@ -802,20 +802,6 @@ void bdrv_dec_in_flight(BlockDriverState *bs) + bdrv_wakeup(bs); + } + +-static void coroutine_fn +-bdrv_wait_serialising_requests(BdrvTrackedRequest *self) +-{ +- BlockDriverState *bs = self->bs; +- +- if (!qatomic_read(&bs->serialising_in_flight)) { +- return; +- } +- +- qemu_mutex_lock(&bs->reqs_lock); +- bdrv_wait_serialising_requests_locked(self); +- qemu_mutex_unlock(&bs->reqs_lock); +-} +- + void coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req, + uint64_t align) + { +@@ -1383,8 +1369,6 @@ bdrv_aligned_preadv(BdrvChild *child, BdrvTrackedRequest *req, + * it ensures that the CoR read and write operations are atomic and + * guest writes cannot interleave between them. */ + bdrv_make_request_serialising(req, bdrv_get_cluster_size(bs)); +- } else { +- bdrv_wait_serialising_requests(req); + } + + if (flags & BDRV_REQ_COPY_ON_READ) { +@@ -2021,8 +2005,6 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, int64_t bytes, + } + + bdrv_wait_serialising_requests_locked(req); +- } else { +- bdrv_wait_serialising_requests(req); + } + + assert(req->overlap_offset <= offset); +@@ -3530,7 +3512,6 @@ static int coroutine_fn GRAPH_RDLOCK bdrv_co_copy_range_internal( + + /* BDRV_REQ_SERIALISING is only for write operation */ + assert(!(read_flags & BDRV_REQ_SERIALISING)); +- bdrv_wait_serialising_requests(&req); + + ret = src->bs->drv->bdrv_co_copy_range_from(src->bs, + src, src_offset, diff --git a/debian/patches/extra/0008-block-fix-bdrv_next-skipping-monitor-owned-nodes.patch b/debian/patches/extra/0008-block-fix-bdrv_next-skipping-monitor-owned-nodes.patch new file mode 100644 index 0000000000..09bc3f3d7d --- /dev/null +++ b/debian/patches/extra/0008-block-fix-bdrv_next-skipping-monitor-owned-nodes.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Denis V. Lunev" +Date: Sat, 29 Aug 2026 00:20:05 +0200 +Subject: [PATCH] block: fix bdrv_next() skipping monitor-owned nodes + +it->bs is the cursor into monitor_bdrv_states for the second phase of +bdrv_next(), so it has to be NULL when that phase starts. Commit +f6d38c9f6d made the first phase store the node it returns there, to +unreference the right one when the graph changes underneath. The cursor +is now left pointing at the last BlockBackend root, so the second phase +resumes from there instead of from the head of the list and never +returns a node added before it. + +A skipped node drops out of the vm_stop and migration handover paths: +not flushed, not inactivated, not snapshotted. bdrv_inactivate_all() +still reports success, so the node keeps its image lock and the +migration target cannot open the image. Only detached nodes are hit in +practice, as these callers also recurse into children. + +Reset the cursor when the second phase starts. old_bs is taken at the +top of the function, so f6d38c9f6d keeps working. + +Cc: qemu-stable@nongnu.org +Fixes: f6d38c9f6d ("block-backend: fix edge case in bdrv_next() where BDS associated to BB changes") +Signed-off-by: Denis V. Lunev +Cc: Fiona Ebner +Cc: Kevin Wolf +Message-ID: <20260828222005.2888213-1-den@openvz.org> +Reviewed-by: Fiona Ebner +Tested-by: Fiona Ebner +Reviewed-by: Kevin Wolf +Signed-off-by: Kevin Wolf +(cherry picked from commit 8daaf8d3b1c5f2ef98e526e036277083bc5fe34b) +Signed-off-by: Fiona Ebner +--- + block/block-backend.c | 1 + + tests/qemu-iotests/tests/inactive-node-nbd | 16 ++++++++++++++++ + tests/qemu-iotests/tests/inactive-node-nbd.out | 8 ++++++++ + 3 files changed, 25 insertions(+) + +diff --git a/block/block-backend.c b/block/block-backend.c +index 37ba7e9fc4..55497c4551 100644 +--- a/block/block-backend.c ++++ b/block/block-backend.c +@@ -625,6 +625,7 @@ BlockDriverState *bdrv_next(BdrvNextIterator *it) + return bs; + } + it->phase = BDRV_NEXT_MONITOR_OWNED; ++ it->bs = NULL; + } + + /* Then return the monitor-owned BDSes without a BB attached. Ignore all +diff --git a/tests/qemu-iotests/tests/inactive-node-nbd b/tests/qemu-iotests/tests/inactive-node-nbd +index 664157bfd0..ef876ae6be 100755 +--- a/tests/qemu-iotests/tests/inactive-node-nbd ++++ b/tests/qemu-iotests/tests/inactive-node-nbd +@@ -47,6 +47,7 @@ def node_is_active(_vm, node_name): + return node['active'] + + with iotests.FilePath('disk.img') as path, \ ++ iotests.FilePath('detached.img') as detached_path, \ + iotests.FilePath('snap.qcow2') as snap_path, \ + iotests.FilePath('snap2.qcow2') as snap2_path, \ + iotests.FilePath('target.img') as target_path, \ +@@ -58,6 +59,7 @@ with iotests.FilePath('disk.img') as path, \ + iotests.log('Preparing disk...') + iotests.qemu_img_create('-f', iotests.imgfmt, path, img_size) + iotests.qemu_img_create('-f', iotests.imgfmt, target_path, img_size) ++ iotests.qemu_img_create('-f', iotests.imgfmt, detached_path, img_size) + + iotests.qemu_img_create('-f', 'qcow2', '-b', path, '-F', iotests.imgfmt, + snap_path) +@@ -68,6 +70,9 @@ with iotests.FilePath('disk.img') as path, \ + vm.add_blockdev(f'file,node-name=disk-file,filename={path}') + vm.add_blockdev(f'{iotests.imgfmt},file=disk-file,node-name=disk-fmt,' + 'active=off') ++ vm.add_blockdev(f'file,node-name=detached-file,filename={detached_path}') ++ vm.add_blockdev(f'{iotests.imgfmt},file=detached-file,' ++ 'node-name=detached-fmt') + vm.add_blockdev(f'file,node-name=target-file,filename={target_path}') + vm.add_blockdev(f'{iotests.imgfmt},file=target-file,node-name=target-fmt') + vm.add_blockdev(f'file,node-name=snap-file,filename={snap_path}') +@@ -297,6 +302,17 @@ with iotests.FilePath('disk.img') as path, \ + iotests.log('snap2-fmt active: %s' % node_is_active(vm, 'snap2-fmt')) + iotests.log('target-fmt active: %s' % node_is_active(vm, 'target-fmt')) + ++ iotests.log('\n=== Inactivating all nodes at once ===') ++ ++ # detached-fmt has no parent and no BlockBackend, so nothing can reach it ++ # by recursion. It is only inactivated if bdrv_next() actually returns it. ++ vm.qmp_log('stop') ++ vm.qmp_log('blockdev-set-active', active=False) ++ ++ iotests.log('detached-fmt active: %s' % node_is_active(vm, 'detached-fmt')) ++ iotests.log('detached-file active: %s' ++ % node_is_active(vm, 'detached-file')) ++ + iotests.log('\nShutting down...') + vm.shutdown() + log = vm.get_log() +diff --git a/tests/qemu-iotests/tests/inactive-node-nbd.out b/tests/qemu-iotests/tests/inactive-node-nbd.out +index a458b4fc05..48451dc0c5 100644 +--- a/tests/qemu-iotests/tests/inactive-node-nbd.out ++++ b/tests/qemu-iotests/tests/inactive-node-nbd.out +@@ -235,5 +235,13 @@ snap-fmt active: True + snap2-fmt active: True + target-fmt active: True + ++=== Inactivating all nodes at once === ++{"execute": "stop", "arguments": {}} ++{"return": {}} ++{"execute": "blockdev-set-active", "arguments": {"active": false}} ++{"return": {}} ++detached-fmt active: False ++detached-file active: False ++ + Shutting down... + diff --git a/debian/patches/extra/0009-iotests-add-test-cases-for-failing-flush-after-qemu-.patch b/debian/patches/extra/0009-iotests-add-test-cases-for-failing-flush-after-qemu-.patch new file mode 100644 index 0000000000..b25ebdf1b9 --- /dev/null +++ b/debian/patches/extra/0009-iotests-add-test-cases-for-failing-flush-after-qemu-.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fiona Ebner +Date: Thu, 8 Oct 2026 08:11:42 -0500 +Subject: [PATCH] iotests: add test cases for failing flush after qemu-img + convert + +In preparation to add more checks in the following commits and show +how the behavior changes. + +Signed-off-by: Fiona Ebner +Message-ID: <20260930132140.2342574-2-f.ebner@proxmox.com> +Reviewed-by: Eric Blake +Signed-off-by: Eric Blake +Link: https://lore.kernel.org/qemu-devel/20261008131216.2437896-20-eblake@redhat.com +(pick from qemu-devel) +Signed-off-by: Fiona Ebner +--- + tests/qemu-iotests/122 | 33 +++++++++++++++++++++++++++++++++ + tests/qemu-iotests/122.out | 14 ++++++++++++++ + 2 files changed, 47 insertions(+) + +diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 +index be0f6b79e5..488649f1bd 100755 +--- a/tests/qemu-iotests/122 ++++ b/tests/qemu-iotests/122 +@@ -334,6 +334,39 @@ echo + $QEMU_IMG convert -O $IMGFMT -o preallocation=metadata -n \ + "$TEST_IMG" "$TEST_IMG".orig && echo "unexpected success" + ++echo ++echo "=== failing flush after convert with default ('unsafe') cache mode ===" ++echo ++ ++TEST_IMG="$TEST_IMG".orig _make_test_img 1M ++TEST_IMG="$TEST_IMG" _make_test_img 1M ++ ++$QEMU_IO -c "write -P 42 0 1M" "$TEST_IMG".orig | _filter_qemu_io ++ ++target_fails_flush="json:{ ++ 'driver': '$IMGFMT', ++ 'file': { ++ 'driver': 'blkdebug', ++ 'inject-error': [{ ++ 'event': 'flush_to_disk' ++ }], ++ 'image': { ++ 'driver': 'file', ++ 'filename': '$TEST_IMG' ++ } ++ } ++}" ++ ++$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG".orig "$target_fails_flush" ++echo "qemu-img convert exited with status $?" ++ ++echo ++echo "=== failing flush after convert with 'writeback' cache mode ===" ++echo ++ ++$QEMU_IMG convert -t writeback -f $IMGFMT -O $IMGFMT -n "$TEST_IMG".orig "$target_fails_flush" ++echo "qemu-img convert exited with status $?" ++ + # success, all done + echo '*** done' + rm -f $seq.full +diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out +index 6a1aa3fe2b..f3e28f33bc 100644 +--- a/tests/qemu-iotests/122.out ++++ b/tests/qemu-iotests/122.out +@@ -256,4 +256,18 @@ Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 + === -n incompatible with -o === + + qemu-img: -o has no effect when skipping image creation ++ ++=== failing flush after convert with default ('unsafe') cache mode === ++ ++Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=1048576 ++Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 ++wrote 1048576/1048576 bytes at offset 0 ++1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++qemu-img convert exited with status 0 ++ ++=== failing flush after convert with 'writeback' cache mode === ++ ++qemu-img: Failed to flush the L2 table cache: Input/output error ++qemu-img: Failed to flush the refcount block cache: Input/output error ++qemu-img convert exited with status 0 + *** done diff --git a/debian/patches/extra/0010-iotests.py-add-filter_qemu.patch b/debian/patches/extra/0010-iotests.py-add-filter_qemu.patch new file mode 100644 index 0000000000..73f0cfab1f --- /dev/null +++ b/debian/patches/extra/0010-iotests.py-add-filter_qemu.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fiona Ebner +Date: Thu, 8 Oct 2026 08:11:43 -0500 +Subject: [PATCH] iotests.py: add filter_qemu() + +Add a filter_qemu() helper function for replacing the QEMU program +name with 'QEMU_PROG' in test's log messages. + +Signed-off-by: Fiona Ebner +Message-ID: <20260930132140.2342574-3-f.ebner@proxmox.com> +Reviewed-by: Eric Blake +Signed-off-by: Eric Blake +Link: https://lore.kernel.org/qemu-devel/20261008131216.2437896-21-eblake@redhat.com +(pick from qemu-devel) +Signed-off-by: Fiona Ebner +--- + tests/qemu-iotests/iotests.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py +index 072be80e07..ed41f88d2a 100644 +--- a/tests/qemu-iotests/iotests.py ++++ b/tests/qemu-iotests/iotests.py +@@ -596,6 +596,10 @@ def filter_qemu_io(msg): + return qemu_io_re.sub("X ops; XX:XX:XX.X " + "(XXX YYY/sec and XXX ops/sec)", msg) + ++qemu_re = re.compile(r"%s" % os.path.basename(qemu_prog)) ++def filter_qemu(msg): ++ return qemu_re.sub("QEMU_PROG", msg) ++ + chown_re = re.compile(r"chown [0-9]+:[0-9]+") + def filter_chown(msg): + return chown_re.sub("chown UID:GID", msg) diff --git a/debian/patches/extra/0011-block-report-flush-error-during-bdrv_close.patch b/debian/patches/extra/0011-block-report-flush-error-during-bdrv_close.patch new file mode 100644 index 0000000000..0d1d3d3df0 --- /dev/null +++ b/debian/patches/extra/0011-block-report-flush-error-during-bdrv_close.patch @@ -0,0 +1,763 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fiona Ebner +Date: Thu, 8 Oct 2026 08:11:44 -0500 +Subject: [PATCH] block: report flush error during bdrv_close() + +Flush during bdrv_close() was introduced back in 2012 in commit +80ccf93b88 ("qemu-img: let 'qemu-img convert' flush data"). However, a +failing flush was quietly ignored [0]. Report the error instead, since +this could mean that the image contents are not as expected. + +Adapt the iotests accordingly. For all tests except '080' and +'qsd-migrate' the failures come from blkdebug configurations. For +'080', the failures are also directly expected, because of invalid L1 +table size and offset. For the 'qsd-migrate' test, the error happens, +because the QSD node which is attached via NBD to the source VM was +inactivated. + +[0]: Note that the errors reported for qcow2 come from +qcow2_inactivate() which is only called as part of +bs->drv->bdrv_close() after bdrv_flush(). In particular, adding +> 'once': 'on' +to the blkdebug driver in the relevant test case in the 122 iotest +shows that the failure can be silent in case of qcow2 too. + +Signed-off-by: Fiona Ebner +Message-ID: <20260930132140.2342574-4-f.ebner@proxmox.com> +Reviewed-by: Eric Blake +Signed-off-by: Eric Blake +Link: https://lore.kernel.org/qemu-devel/20261008131216.2437896-22-eblake@redhat.com +(pick from qemu-devel) +Signed-off-by: Fiona Ebner +--- + block.c | 13 +++- + tests/qemu-iotests/026 | 10 +-- + tests/qemu-iotests/026.out | 84 ++++++++++++++++++++++ + tests/qemu-iotests/071 | 2 +- + tests/qemu-iotests/071.out | 2 + + tests/qemu-iotests/080.out | 2 + + tests/qemu-iotests/098.out | 4 ++ + tests/qemu-iotests/122 | 8 +-- + tests/qemu-iotests/122.out | 2 + + tests/qemu-iotests/244 | 2 +- + tests/qemu-iotests/244.out | 1 + + tests/qemu-iotests/tests/file-io-error | 2 +- + tests/qemu-iotests/tests/file-io-error.out | 2 + + tests/qemu-iotests/tests/qsd-migrate | 5 +- + tests/qemu-iotests/tests/qsd-migrate.out | 1 + + 15 files changed, 125 insertions(+), 15 deletions(-) + +diff --git a/block.c b/block.c +index f0a6042e61..c05ad01f25 100644 +--- a/block.c ++++ b/block.c +@@ -5162,12 +5162,23 @@ static void GRAPH_UNLOCKED bdrv_close(BlockDriverState *bs) + { + BdrvAioNotifier *ban, *ban_next; + BdrvChild *child, *next; ++ int ret; + + GLOBAL_STATE_CODE(); + assert(!bs->refcnt); + + bdrv_drained_begin(bs); /* complete I/O */ +- bdrv_flush(bs); ++ ret = bdrv_flush(bs); ++ if (ret < 0) { ++ const char *name; ++ if (bs->filename[0]) { ++ name = bs->filename; ++ } else { ++ name = bdrv_get_node_name(bs); ++ } ++ error_report("Failed flush for '%s' during close: %s", name, ++ strerror(-ret)); ++ } + bdrv_drain(bs); /* in case flush left pending I/O */ + + if (bs->drv) { +diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026 +index d37e266dad..88cb4dd934 100755 +--- a/tests/qemu-iotests/026 ++++ b/tests/qemu-iotests/026 +@@ -103,13 +103,13 @@ if [ "$event" == "l2_update" ]; then + $QEMU_IO -c "write $vmstate 0 512" "$TEST_IMG" > /dev/null 2>&1 + fi + +-$QEMU_IO -c "write $vmstate 0 128k " "$BLKDBG_TEST_IMG" | _filter_qemu_io ++$QEMU_IO -c "write $vmstate 0 128k " "$BLKDBG_TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir + + # l2_load is not called on allocation, so issue a second write + # Reads are another path to trigger l2_load, so do a read, too + if [ "$event" == "l2_load" ]; then +- $QEMU_IO -c "write $vmstate 0 128k " "$BLKDBG_TEST_IMG" | _filter_qemu_io +- $QEMU_IO -c "read $vmstate 0 128k " "$BLKDBG_TEST_IMG" | _filter_qemu_io ++ $QEMU_IO -c "write $vmstate 0 128k " "$BLKDBG_TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir ++ $QEMU_IO -c "read $vmstate 0 128k " "$BLKDBG_TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir + fi + + _check_test_img_ignore_leaks 2>&1 | grep -v "refcount=1 reference=0" +@@ -155,7 +155,7 @@ _make_test_img 1G + + echo + echo "Event: $event; errno: $errno; imm: $imm; once: $once; write $vmstate" +-$QEMU_IO -c "write $vmstate 0 64M" "$BLKDBG_TEST_IMG" | _filter_qemu_io ++$QEMU_IO -c "write $vmstate 0 64M" "$BLKDBG_TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir + + _check_test_img_ignore_leaks 2>&1 | grep -v "refcount=1 reference=0" + +@@ -194,7 +194,7 @@ _make_test_img 1G + + echo + echo "Event: $event; errno: $errno; imm: $imm; once: $once" +-$QEMU_IO -c "write -b 0 64k" "$BLKDBG_TEST_IMG" | _filter_qemu_io ++$QEMU_IO -c "write -b 0 64k" "$BLKDBG_TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir + + _check_test_img_ignore_leaks 2>&1 | grep -v "refcount=1 reference=0" + +diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out +index 83989996ff..a92286fab5 100644 +--- a/tests/qemu-iotests/026.out ++++ b/tests/qemu-iotests/026.out +@@ -14,15 +14,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l1_update; errno: 5; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l1_update; errno: 5; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -38,15 +42,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l1_update; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l1_update; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -126,15 +134,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l2_update; errno: 5; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l2_update; errno: 5; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -150,15 +162,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l2_update; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l2_update; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -174,15 +190,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l2_alloc_write; errno: 5; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l2_alloc_write; errno: 5; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -198,15 +218,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l2_alloc_write; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l2_alloc_write; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -222,15 +246,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: write_aio; errno: 5; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: write_aio; errno: 5; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -246,15 +274,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: write_aio; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: write_aio; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -270,15 +302,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_load; errno: 5; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_load; errno: 5; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -294,15 +330,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_load; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_load; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -318,15 +358,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_update_part; errno: 5; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_update_part; errno: 5; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -342,15 +386,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_update_part; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_update_part; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -366,15 +414,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc; errno: 5; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc; errno: 5; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -390,15 +442,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -457,15 +513,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -481,15 +541,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_write; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_write; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -505,15 +569,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -529,15 +597,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -553,15 +625,19 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write -b ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + +@@ -595,8 +671,10 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l1_grow_write_table; errno: 5; imm: off; once: off ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -607,8 +685,10 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l1_grow_write_table; errno: 28; imm: off; once: off ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -619,8 +699,10 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l1_grow_activate_table; errno: 5; imm: off; once: off ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + qemu-io: Failed to flush the L2 table cache: Input/output error + qemu-io: Failed to flush the refcount block cache: Input/output error ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: Input/output error + write failed: Input/output error + No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +@@ -631,8 +713,10 @@ No errors were found on the image. + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 + + Event: l1_grow_activate_table; errno: 28; imm: off; once: off ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + qemu-io: Failed to flush the L2 table cache: No space left on device + qemu-io: Failed to flush the refcount block cache: No space left on device ++qemu-io: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.qcow2' during close: No space left on device + write failed: No space left on device + No errors were found on the image. + +diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 +index 331f8cfddc..3058db5bce 100755 +--- a/tests/qemu-iotests/071 ++++ b/tests/qemu-iotests/071 +@@ -53,7 +53,7 @@ do_run_qemu() + + run_qemu() + { +- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp | _filter_qemu_io ++ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp | _filter_qemu_io | _filter_json_filename + } + + IMG_SIZE=64M +diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out +index a2923b05c2..4014ae2bb3 100644 +--- a/tests/qemu-iotests/071.out ++++ b/tests/qemu-iotests/071.out +@@ -85,8 +85,10 @@ wrote 512/512 bytes at offset 0 + read failed: Input/output error + {"return": ""} + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}} ++QEMU_PROG: Failed flush for 'json:{ /* filtered */ }' during close: Input/output error + QEMU_PROG: Failed to flush the L2 table cache: Input/output error + QEMU_PROG: Failed to flush the refcount block cache: Input/output error ++QEMU_PROG: Failed flush for 'json:{ /* filtered */ }' during close: Input/output error + {"return": {}} + + *** done +diff --git a/tests/qemu-iotests/080.out b/tests/qemu-iotests/080.out +index d8acb3e723..4534ca1219 100644 +--- a/tests/qemu-iotests/080.out ++++ b/tests/qemu-iotests/080.out +@@ -66,6 +66,7 @@ wrote 512/512 bytes at offset 0 + qemu-img: Failed to load snapshot: Snapshot L1 table offset invalid + qemu-img: Snapshot L1 table offset invalid + qemu-img: Failed to turn zero into data clusters: Invalid argument ++qemu-io: Failed flush for 'TEST_DIR/t.qcow2' during close: Invalid argument + qemu-io: Failed to flush the refcount block cache: Invalid argument + write failed: Invalid argument + qemu-img: Snapshot L1 table offset invalid +@@ -89,6 +90,7 @@ wrote 512/512 bytes at offset 0 + qemu-img: Failed to load snapshot: Snapshot L1 table too large + qemu-img: Snapshot L1 table too large + qemu-img: Failed to turn zero into data clusters: File too large ++qemu-io: Failed flush for 'TEST_DIR/t.qcow2' during close: File too large + qemu-io: Failed to flush the refcount block cache: File too large + write failed: File too large + qemu-img: Snapshot L1 table too large +diff --git a/tests/qemu-iotests/098.out b/tests/qemu-iotests/098.out +index 6c73dd0977..912b0290af 100644 +--- a/tests/qemu-iotests/098.out ++++ b/tests/qemu-iotests/098.out +@@ -6,6 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT + wrote 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++qemu-img: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT' during close: Input/output error + qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error + No errors were found on the image. + +@@ -15,6 +16,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT + wrote 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++qemu-img: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT' during close: Input/output error + qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error + Leaked cluster 4 refcount=1 reference=0 + Leaked cluster 5 refcount=1 reference=0 +@@ -28,6 +30,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT + wrote 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++qemu-img: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT' during close: Input/output error + qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error + ERROR cluster 0 refcount=0 reference=1 + ERROR cluster 1 refcount=0 reference=1 +@@ -42,6 +45,7 @@ Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 + Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT + wrote 65536/65536 bytes at offset 0 + 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++qemu-img: Failed flush for 'blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT' during close: Input/output error + qemu-img: Failed to empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error + ERROR cluster 0 refcount=0 reference=1 + ERROR cluster 1 refcount=0 reference=1 +diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 +index 488649f1bd..9da1246f09 100755 +--- a/tests/qemu-iotests/122 ++++ b/tests/qemu-iotests/122 +@@ -357,15 +357,15 @@ target_fails_flush="json:{ + } + }" + +-$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG".orig "$target_fails_flush" +-echo "qemu-img convert exited with status $?" ++$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG".orig "$target_fails_flush" 2>&1 | _filter_json_filename ++echo "qemu-img convert exited with status ${PIPESTATUS[0]}" + + echo + echo "=== failing flush after convert with 'writeback' cache mode ===" + echo + +-$QEMU_IMG convert -t writeback -f $IMGFMT -O $IMGFMT -n "$TEST_IMG".orig "$target_fails_flush" +-echo "qemu-img convert exited with status $?" ++$QEMU_IMG convert -t writeback -f $IMGFMT -O $IMGFMT -n "$TEST_IMG".orig "$target_fails_flush" 2>&1 | _filter_json_filename ++echo "qemu-img convert exited with status ${PIPESTATUS[0]}" + + # success, all done + echo '*** done' +diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out +index f3e28f33bc..84283f2434 100644 +--- a/tests/qemu-iotests/122.out ++++ b/tests/qemu-iotests/122.out +@@ -267,7 +267,9 @@ qemu-img convert exited with status 0 + + === failing flush after convert with 'writeback' cache mode === + ++qemu-img: Failed flush for 'json:{ /* filtered */ }' during close: Input/output error + qemu-img: Failed to flush the L2 table cache: Input/output error + qemu-img: Failed to flush the refcount block cache: Input/output error ++qemu-img: Failed flush for 'json:{ /* filtered */ }' during close: Input/output error + qemu-img convert exited with status 0 + *** done +diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244 +index 2a98ad58f5..ef32f8ec03 100755 +--- a/tests/qemu-iotests/244 ++++ b/tests/qemu-iotests/244 +@@ -264,7 +264,7 @@ $QEMU_IO -c 'write 0 512' -c flush \ + } + } + }" \ +- | _filter_qemu_io ++ 2>&1 | _filter_qemu_io | _filter_generated_node_ids + + result=${PIPESTATUS[0]} + echo +diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out +index c62f5aec25..8935f544cd 100644 +--- a/tests/qemu-iotests/244.out ++++ b/tests/qemu-iotests/244.out +@@ -134,6 +134,7 @@ Images are identical. + + === Flushing should flush the data file === + ++qemu-io: Failed flush for 'NODE_NAME' during close: Input/output error + wrote 512/512 bytes at offset 0 + 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +diff --git a/tests/qemu-iotests/tests/file-io-error b/tests/qemu-iotests/tests/file-io-error +index 0d970c102f..3885b741d9 100755 +--- a/tests/qemu-iotests/tests/file-io-error ++++ b/tests/qemu-iotests/tests/file-io-error +@@ -94,7 +94,7 @@ echo "$output" + + echo + # This should fail, but gracefully, i.e. just print an I/O error, not crash. +-$QEMU_IO -f file -c 'write 0 64M' "$TEST_DIR/fuse-export" | _filter_qemu_io ++$QEMU_IO -f file -c 'write 0 64M' "$TEST_DIR/fuse-export" 2>&1 | _filter_qemu_io | _filter_testdir + echo + + capture_events=BLOCK_EXPORT_DELETED _send_qemu_cmd $QEMU_HANDLE \ +diff --git a/tests/qemu-iotests/tests/file-io-error.out b/tests/qemu-iotests/tests/file-io-error.out +index 0f46455a94..b5ac8d3db1 100644 +--- a/tests/qemu-iotests/tests/file-io-error.out ++++ b/tests/qemu-iotests/tests/file-io-error.out +@@ -21,6 +21,7 @@ QA output created by file-io-error + }} + {"return": {}} + ++qemu-io: Failed flush for 'TEST_DIR/fuse-export' during close: Input/output error + write failed: Input/output error + + {'execute': 'block-export-del', +@@ -29,5 +30,6 @@ write failed: Input/output error + {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "exp0"}} + {'execute': 'blockdev-del', + 'arguments': {'node-name': 'node0'}} ++QEMU_PROG: Failed flush for 'node0' during close: Input/output error + {"return": {}} + *** done +diff --git a/tests/qemu-iotests/tests/qsd-migrate b/tests/qemu-iotests/tests/qsd-migrate +index a4c6592420..3fb5b2e475 100755 +--- a/tests/qemu-iotests/tests/qsd-migrate ++++ b/tests/qemu-iotests/tests/qsd-migrate +@@ -20,7 +20,7 @@ + + import iotests + +-from iotests import filter_qemu_io, filter_qtest ++from iotests import filter_qemu, filter_qemu_io, filter_qtest + + iotests.script_initialize(supported_fmts=['qcow2', 'qed', 'raw'], + supported_protocols=['file'], +@@ -125,11 +125,12 @@ with iotests.FilePath('disk.img') as path, \ + + iotests.log('\nDone') + ++ # NOTE: Flush during close fails here, since the QSD node was inactivated. + vm_src.shutdown() + iotests.log('\n--- vm_src log ---') + log = vm_src.get_log() + if log: +- iotests.log(log, [filter_qtest, filter_qemu_io]) ++ iotests.log(log, [filter_qtest, filter_qemu_io, filter_qemu]) + qsd_src.stop() + + vm_dst.shutdown() +diff --git a/tests/qemu-iotests/tests/qsd-migrate.out b/tests/qemu-iotests/tests/qsd-migrate.out +index 4a5241e5d4..894b232b4a 100644 +--- a/tests/qemu-iotests/tests/qsd-migrate.out ++++ b/tests/qemu-iotests/tests/qsd-migrate.out +@@ -47,6 +47,7 @@ read 4096/4096 bytes at offset 0 + 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + read 4096/4096 bytes at offset 0 + 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) ++QEMU_PROG: Failed flush for 'disk' during close: Operation not permitted + + --- vm_dst log --- + read 4096/4096 bytes at offset 0 diff --git a/debian/patches/extra/0012-qemu-img-convert-flush-target-image-after-copying.patch b/debian/patches/extra/0012-qemu-img-convert-flush-target-image-after-copying.patch new file mode 100644 index 0000000000..b7962dfd96 --- /dev/null +++ b/debian/patches/extra/0012-qemu-img-convert-flush-target-image-after-copying.patch @@ -0,0 +1,99 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fiona Ebner +Date: Thu, 8 Oct 2026 08:11:45 -0500 +Subject: [PATCH] qemu-img: convert: flush target image after copying + +With 'qemu-img convert', when using a cache mode with 'cache.no-flush += off', the expectation is that the data is flushed to the disk, which +happens since commit 80ccf93b88 ("qemu-img: let 'qemu-img convert' +flush data"). This expectation also encompasses that failure to do so +is properly reported, so ensure that 'qemu-img convert' exits with a +non-zero status code when the target image cannot be flushed. + +In particular, the reproducer below [0], based on a report by +Ing. Alfonso Kuen Arroyo [1], would result in +> rc=0 +> Content mismatch at offset XYZ! +before this change, and in +> rc=1 +> Content mismatch at offset XYZ! +after this change. + +Note that this change does not affect the (default) 'unsafe' cache +mode, because bdrv_co_flush() still skips flush to disk for that cache +mode. + +[0]: +> #!/bin/bash -x +> dd if=/dev/urandom of=src.raw bs=1M count=500 +> truncate -s 500M dst.img +> LOOP=$(losetup --find --show dst.img) +> SIZE=$(blockdev --getsz $LOOP) +> dd if=/dev/zero of=$LOOP bs=1M count=500 conv=fsync status=none +> sync +> echo 3 > /proc/sys/vm/drop_caches +> dmsetup create flk --table "0 $SIZE flakey $LOOP 0 5 5" +> qemu-img convert -t writeback -p -r 100M -f raw -O raw src.raw /dev/mapper/flk +> echo rc=$? +> sleep 5 +> dmsetup remove flk +> qemu-img compare src.raw $LOOP +> losetup -d $LOOP +> rm src.raw dst.img + +[1]: https://lore.proxmox.com/pve-devel/178961792132.43804.17173233935297903311@idkmanager.com/ + +Signed-off-by: Fiona Ebner +Message-ID: <20260930132140.2342574-5-f.ebner@proxmox.com> +Reviewed-by: Eric Blake +Signed-off-by: Eric Blake +Link: https://lore.kernel.org/qemu-devel/20261008131216.2437896-23-eblake@redhat.com +(pick from qemu-devel) +Signed-off-by: Fiona Ebner +--- + qemu-img.c | 8 +++++++- + tests/qemu-iotests/122.out | 3 ++- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index 2f63d31141..edf75e43ab 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -2245,7 +2245,7 @@ static int img_convert(const img_cmd_t *ccmd, int argc, char **argv) + Error *local_err = NULL; + bool writethrough, src_writethrough, image_opts = false, + skip_create = false, progress = false, tgt_image_opts = false; +- int64_t ret = -EINVAL; ++ int64_t ret = -EINVAL, ret2; + bool force_share = false; + bool explict_min_sparse = false; + bool bitmaps = false; +@@ -2872,6 +2872,12 @@ static int img_convert(const img_cmd_t *ccmd, int argc, char **argv) + ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs, skip_broken); + } + ++ ret2 = blk_flush(s.target); ++ if (ret2 < 0) { ++ error_report("Failed to flush target image: %s", strerror(-ret2)); ++ ret = ret != 0 ? ret : ret2; ++ } ++ + out: + if (!ret) { + qemu_progress_print(100, 0); +diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out +index 84283f2434..38794f96ac 100644 +--- a/tests/qemu-iotests/122.out ++++ b/tests/qemu-iotests/122.out +@@ -267,9 +267,10 @@ qemu-img convert exited with status 0 + + === failing flush after convert with 'writeback' cache mode === + ++qemu-img: Failed to flush target image: Input/output error + qemu-img: Failed flush for 'json:{ /* filtered */ }' during close: Input/output error + qemu-img: Failed to flush the L2 table cache: Input/output error + qemu-img: Failed to flush the refcount block cache: Input/output error + qemu-img: Failed flush for 'json:{ /* filtered */ }' during close: Input/output error +-qemu-img convert exited with status 0 ++qemu-img convert exited with status 1 + *** done diff --git a/debian/patches/extra/0013-qapi-virtio-Restore-backend-features-in-x-query-virt.patch b/debian/patches/extra/0013-qapi-virtio-Restore-backend-features-in-x-query-virt.patch new file mode 100644 index 0000000000..cbee94c9fc --- /dev/null +++ b/debian/patches/extra/0013-qapi-virtio-Restore-backend-features-in-x-query-virt.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Wed, 23 Sep 2026 00:32:09 +0300 +Subject: [PATCH] qapi/virtio: Restore backend features in + x-query-virtio-status + +Commit 1ee0bc0c9bf0 removed vhost_dev.backend_features and its +representation in VhostStatus. It also removed the assignment to +VirtioStatus.backend_features, although both that field and its source, +VirtIODevice.backend_features_ex, still exist. + +The resulting NULL pointer causes HMP info virtio-status and QMP +x-query-virtio-status to crash. This affects virtio devices even without +an active vhost backend. + +Restore the assignment from VirtIODevice.backend_features_ex and +enable corresponding test, which becomes fixed. + +Fixes: 1ee0bc0c9bf0 ("vhost: drop backend_features field") +Signed-off-by: Vladimir Sementsov-Ogievskiy +Link: https://lore.kernel.org/qemu-devel/20260922213210.1429435-3-vsementsov@yandex-team.ru +(pick from qemu-devel) +[FE: drop test that would require multiple prerequisite cherry-picks] +Signed-off-by: Fiona Ebner +--- + hw/virtio/virtio-qmp.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/virtio/virtio-qmp.c b/hw/virtio/virtio-qmp.c +index 57cc03828c..36907180f7 100644 +--- a/hw/virtio/virtio-qmp.c ++++ b/hw/virtio/virtio-qmp.c +@@ -713,6 +713,8 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp) + vdev->guest_features_ex); + status->host_features = qmp_decode_features(vdev->device_id, + vdev->host_features_ex); ++ status->backend_features = qmp_decode_features(vdev->device_id, ++ vdev->backend_features_ex); + + switch (vdev->device_endian) { + case VIRTIO_DEVICE_ENDIAN_LITTLE: diff --git a/debian/patches/extra/0014-qapi-monitor-Handle-missing-vhost-user-protocol-feat.patch b/debian/patches/extra/0014-qapi-monitor-Handle-missing-vhost-user-protocol-feat.patch new file mode 100644 index 0000000000..ce3c49cce0 --- /dev/null +++ b/debian/patches/extra/0014-qapi-monitor-Handle-missing-vhost-user-protocol-feat.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Wed, 23 Sep 2026 00:32:10 +0300 +Subject: [PATCH] qapi/monitor: Handle missing vhost-user protocol features + +Commit f9a8f5812607 moved protocol_features to the vhost-user backend. +As a result, VhostStatus.protocol_features is only populated for +vhost-user devices. + +For an active kernel vhost device, HMP info virtio-status and QMP +x-query-virtio-status crashes now because of unset protocol-features. + +Make protocol-features optional in VhostStatus and skip dumping a +missing object in HMP. + +For QMP we can change the x-query-virtio-status command semantics +because it is unstable. + +Enable corresponding test, it works now. + +Fixes: f9a8f5812607 ("vhost: move protocol_features to vhost_user") +Co-authored-by: Nikolay Kuratov +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Markus Armbruster +Link: https://lore.kernel.org/qemu-devel/20260922213210.1429435-4-vsementsov@yandex-team.ru +(pick from qemu-devel) +[FE: backport adapting to missing monitor_hmp_printf refactor + drop test would require multiple prerequisite cherry-picks] +Signed-off-by: Fiona Ebner +--- + hw/virtio/virtio-hmp-cmds.c | 6 ++++-- + qapi/virtio.json | 5 +++-- + 2 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/virtio-hmp-cmds.c b/hw/virtio/virtio-hmp-cmds.c +index a91bb7dbed..c4adb6eb7b 100644 +--- a/hw/virtio/virtio-hmp-cmds.c ++++ b/hw/virtio/virtio-hmp-cmds.c +@@ -176,8 +176,10 @@ void hmp_virtio_status(Monitor *mon, const QDict *qdict) + hmp_virtio_dump_features(mon, s->vhost_dev->features); + monitor_printf(mon, " Acked features:\n"); + hmp_virtio_dump_features(mon, s->vhost_dev->acked_features); +- monitor_printf(mon, " Protocol features:\n"); +- hmp_virtio_dump_protocols(mon, s->vhost_dev->protocol_features); ++ if (s->vhost_dev->protocol_features) { ++ monitor_printf(mon, " Protocol features:\n"); ++ hmp_virtio_dump_protocols(mon, s->vhost_dev->protocol_features); ++ } + } + + qapi_free_VirtioStatus(s); +diff --git a/qapi/virtio.json b/qapi/virtio.json +index 1fc4e38a44..f8e699a0e4 100644 +--- a/qapi/virtio.json ++++ b/qapi/virtio.json +@@ -85,7 +85,8 @@ + # + # @acked-features: vhost_dev acked_features + # +-# @protocol-features: vhost_dev protocol_features ++# @protocol-features: vhost-user protocol features. Present only for ++# vhost-user devices. + # + # @max-queues: vhost_dev max_queues + # +@@ -104,7 +105,7 @@ + 'vq-index': 'int', + 'features': 'VirtioDeviceFeatures', + 'acked-features': 'VirtioDeviceFeatures', +- 'protocol-features': 'VhostDeviceProtocols', ++ '*protocol-features': 'VhostDeviceProtocols', + 'max-queues': 'uint64', + 'backend-cap': 'uint64', + 'log-enabled': 'bool', diff --git a/debian/patches/extra/0015-system-fix-buffer-overflow-in-tdx_parse_panic_messag.patch b/debian/patches/extra/0015-system-fix-buffer-overflow-in-tdx_parse_panic_messag.patch new file mode 100644 index 0000000000..87a1249fa9 --- /dev/null +++ b/debian/patches/extra/0015-system-fix-buffer-overflow-in-tdx_parse_panic_messag.patch @@ -0,0 +1,100 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Levitsky +Date: Tue, 22 Sep 2026 20:45:53 -0400 +Subject: [PATCH] system: fix buffer overflow in tdx_parse_panic_message + +tdx_parse_panic_message has code that detects if the guest supplied +message contains some unprintable characters and in this case prints a hex dump. + +The code has a bug: it allocates 3 bytes for 'sprintf("%02x ")', +but sprintf in this case actually writes at least 4 bytes, because it adds the NULL +terminator, or even 9 bytes if the char type is signed and the MSB is set. + +To fix this, just use qemu_hexdump_line instead. + +Reported-by: Jordy Zomer +Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3905 +Signed-off-by: Maxim Levitsky +Link: https://lore.kernel.org/r/20260923004553.100732-1-mlevitsk@redhat.com +Signed-off-by: Paolo Bonzini +(cherry picked from commit b7f51182c08123eda612db553e2cded6e536ff49) +Signed-off-by: Fiona Ebner +--- + system/runstate.c | 36 +++++++----------------------------- + 1 file changed, 7 insertions(+), 29 deletions(-) + +diff --git a/system/runstate.c b/system/runstate.c +index 08acf801b0..3c8693ccf3 100644 +--- a/system/runstate.c ++++ b/system/runstate.c +@@ -50,6 +50,7 @@ + #include "qemu/sockets.h" + #include "qemu/timer.h" + #include "qemu/thread.h" ++#include "qemu/cutils.h" + #include "qom/object.h" + #include "qom/object_interfaces.h" + #include "system/cpus.h" +@@ -606,10 +607,9 @@ static void qemu_system_wakeup(void) + } + } + +-static char *tdx_parse_panic_message(char *message) ++static GString *tdx_parse_panic_message(char *message) + { + bool printable = false; +- char *buf = NULL; + int len = 0, i; + + /* +@@ -630,32 +630,11 @@ static char *tdx_parse_panic_message(char *message) + } + } + +- if (len == 0) { +- buf = g_malloc(1); +- buf[0] = '\0'; ++ if (printable) { ++ return g_string_new(message); + } else { +- if (!printable) { +- /* 3 = length of "%02x " */ +- buf = g_malloc(len * 3); +- for (i = 0; i < len; i++) { +- if (message[i] == '\0') { +- break; +- } else { +- sprintf(buf + 3 * i, "%02x ", message[i]); +- } +- } +- if (i > 0) { +- /* replace the last ' '(space) to NULL */ +- buf[i * 3 - 1] = '\0'; +- } else { +- buf[0] = '\0'; +- } +- } else { +- buf = g_strdup(message); +- } ++ return qemu_hexdump_line(NULL, message, len, 1, 0); + } +- +- return buf; + } + + void qemu_system_guest_panicked(GuestPanicInformation *info) +@@ -700,12 +679,11 @@ void qemu_system_guest_panicked(GuestPanicInformation *info) + info->u.s390.psw_mask, + info->u.s390.psw_addr); + } else if (info->type == GUEST_PANIC_INFORMATION_TYPE_TDX) { +- char *message = tdx_parse_panic_message(info->u.tdx.message); ++ g_autoptr(GString) message = tdx_parse_panic_message(info->u.tdx.message); + qemu_log_mask(LOG_GUEST_ERROR, + "\nTDX guest reports fatal error." + " error code: 0x%" PRIx32 " error message:\"%s\"\n", +- info->u.tdx.error_code, message); +- g_free(message); ++ info->u.tdx.error_code, message->str); + if (info->u.tdx.has_gpa) { + qemu_log_mask(LOG_GUEST_ERROR, "Additional error information " + "can be found at gpa page: 0x%" PRIx64 "\n", diff --git a/debian/patches/extra/0016-accel-kvm-protect-kvm_resample_fd_list-with-a-mutex.patch b/debian/patches/extra/0016-accel-kvm-protect-kvm_resample_fd_list-with-a-mutex.patch new file mode 100644 index 0000000000..34b38927df --- /dev/null +++ b/debian/patches/extra/0016-accel-kvm-protect-kvm_resample_fd_list-with-a-mutex.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Levitsky +Date: Tue, 22 Sep 2026 20:46:51 -0400 +Subject: [PATCH] accel/kvm: protect kvm_resample_fd_list with a mutex + +Legacy PCI INTx interrupts are level triggered and can, in theory, be shared. + +Upon receiving such an interrupt, VFIO kernel driver masks it in a generic way, +using INTX_DISABLE bit in the PCI config space. + +It then waits for the guest to signal completion (EOI) of the interrupt, +upon which VFIO re-enables the interrupt. + +The completion is signaled with another eventfd. + +For split irqchip mode, KVM doesn't have a notion of EOI on IOAPIC level. +Instead it signals EOI with a userspace VM exit, KVM_EXIT_IOAPIC_EOI. + +Upon receiving this VM exit, Qemu manually signals the above-mentioned eventfd. + +The problem that this patch resolves is that QEMU keeps these eventfds in +a linked list without any locking to prevent the list from being corrupted by +concurrent access. + +Such use is possible and guest triggerable if the guest rapidly toggles +INTX mode of a VFIO device and at the same time signals EOI with an arbitrary +vector. + +Fix this by protecting this list (kvm_resample_fd_list) with a mutex. + +This patch was only compile tested. + +Reported-by: "Vulnerability Report" +Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3942 +Signed-off-by: Maxim Levitsky +Link: https://lore.kernel.org/r/20260923004651.101197-1-mlevitsk@redhat.com +Signed-off-by: Paolo Bonzini +(cherry picked from commit 0f98b46846eb04791f5f4c992d3441c8a8b48872) +Signed-off-by: Fiona Ebner +--- + accel/kvm/kvm-all.c | 14 +++++++++++++- + hw/intc/ioapic.c | 6 +++--- + 2 files changed, 16 insertions(+), 4 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index 83cbd120a8..da3afdc68d 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -146,6 +146,7 @@ typedef struct KVMResampleFd KVMResampleFd; + static QLIST_HEAD(, KVMResampleFd) kvm_resample_fd_list = + QLIST_HEAD_INITIALIZER(kvm_resample_fd_list); + ++static QemuMutex kvm_resample_fd_list_lock; + static QemuMutex kml_slots_lock; + + #define kvm_slots_lock() qemu_mutex_lock(&kml_slots_lock) +@@ -157,6 +158,8 @@ static inline void kvm_resample_fd_remove(int gsi) + { + KVMResampleFd *rfd; + ++ qemu_mutex_lock(&kvm_resample_fd_list_lock); ++ + QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) { + if (rfd->gsi == gsi) { + QLIST_REMOVE(rfd, node); +@@ -164,6 +167,8 @@ static inline void kvm_resample_fd_remove(int gsi) + break; + } + } ++ ++ qemu_mutex_unlock(&kvm_resample_fd_list_lock); + } + + static inline void kvm_resample_fd_insert(int gsi, EventNotifier *event) +@@ -173,20 +178,26 @@ static inline void kvm_resample_fd_insert(int gsi, EventNotifier *event) + rfd->gsi = gsi; + rfd->resample_event = event; + ++ qemu_mutex_lock(&kvm_resample_fd_list_lock); + QLIST_INSERT_HEAD(&kvm_resample_fd_list, rfd, node); ++ qemu_mutex_unlock(&kvm_resample_fd_list_lock); + } + + void kvm_resample_fd_notify(int gsi) + { + KVMResampleFd *rfd; + ++ qemu_mutex_lock(&kvm_resample_fd_list_lock); ++ + QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) { + if (rfd->gsi == gsi) { + event_notifier_set(rfd->resample_event); + trace_kvm_resample_fd_notify(gsi); +- return; ++ break; + } + } ++ ++ qemu_mutex_unlock(&kvm_resample_fd_list_lock); + } + + /** +@@ -2910,6 +2921,7 @@ static int kvm_init(AccelState *as, MachineState *ms) + int type; + + qemu_mutex_init(&kml_slots_lock); ++ qemu_mutex_init(&kvm_resample_fd_list_lock); + + /* + * On systems where the kernel can support different base page +diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c +index 1b3f1e824a..1932b14642 100644 +--- a/hw/intc/ioapic.c ++++ b/hw/intc/ioapic.c +@@ -248,7 +248,6 @@ void ioapic_eoi_broadcast(int vector) + continue; + } + +-#ifdef CONFIG_KVM + /* + * When IOAPIC is in the userspace while APIC is still in + * the kernel (i.e., split irqchip), we have a trick to +@@ -264,8 +263,9 @@ void ioapic_eoi_broadcast(int vector) + * operations below because we don't know whether there're + * emulated devices that are using/sharing the same IRQ. + */ +- kvm_resample_fd_notify(n); +-#endif ++ if (kvm_enabled()) { ++ kvm_resample_fd_notify(n); ++ } + + if (!(entry & IOAPIC_LVT_REMOTE_IRR)) { + continue; diff --git a/debian/patches/extra/0017-accel-kvm-coalesced-mmio-check-lenght-of-the-MMIO-wr.patch b/debian/patches/extra/0017-accel-kvm-coalesced-mmio-check-lenght-of-the-MMIO-wr.patch new file mode 100644 index 0000000000..889cdf040c --- /dev/null +++ b/debian/patches/extra/0017-accel-kvm-coalesced-mmio-check-lenght-of-the-MMIO-wr.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Levitsky +Date: Tue, 22 Sep 2026 20:46:31 -0400 +Subject: [PATCH] accel/kvm: coalesced mmio: check lenght of the MMIO write + entry + +KVM's coalesced mmio ring buffer has entries that contain deffered MMIO +writes. + +Each such entry contains the length, an 8 byte value and a guest address. + +While the length value comes from the kernel, it is still possible for +an attacker to corrupt the length field using another exploit. + +The attacker can then invoke kvm_flush_coalesced_mmio_buffer, which blindly +trusts the length and can be used to inflict further damage. + +Add a sanity check on the length field to prevent this. + +This patch was only compile tested. + +Reported by: "Labs, STAR" +Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3863 +Signed-off-by: Maxim Levitsky +Link: https://lore.kernel.org/r/20260923004631.100997-1-mlevitsk@redhat.com +Signed-off-by: Paolo Bonzini +(cherry picked from commit 12916d64b78ec5dd0171e607ad2ffcc34537f3cf) +Signed-off-by: Fiona Ebner +--- + accel/kvm/kvm-all.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index da3afdc68d..5433a223e3 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -3185,9 +3185,15 @@ void kvm_flush_coalesced_mmio_buffer(void) + const AddressSpace *as; + + ent = &ring->coalesced_mmio[ring->first]; +- as = ent->pio == 1 ? &address_space_io : &address_space_memory; +- address_space_write(as, ent->phys_addr, MEMTXATTRS_UNSPECIFIED, +- ent->data, ent->len); ++ if (ent->len > sizeof(ent->data)) { ++ warn_report("coalesced MMIO entry has invalid len %u", ++ ent->len); ++ } else { ++ as = ent->pio == 1 ? &address_space_io : &address_space_memory; ++ address_space_write(as, ent->phys_addr, MEMTXATTRS_UNSPECIFIED, ++ ent->data, ent->len); ++ } ++ + smp_wmb(); + ring->first = (ring->first + 1) % KVM_COALESCED_MMIO_MAX; + } diff --git a/debian/patches/pve/0006-PVE-Up-qemu-img-return-success-on-info-without-snaps.patch b/debian/patches/pve/0006-PVE-Up-qemu-img-return-success-on-info-without-snaps.patch index e872eb361d..0c61285b6f 100644 --- a/debian/patches/pve/0006-PVE-Up-qemu-img-return-success-on-info-without-snaps.patch +++ b/debian/patches/pve/0006-PVE-Up-qemu-img-return-success-on-info-without-snaps.patch @@ -9,10 +9,10 @@ Signed-off-by: Thomas Lamprecht 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu-img.c b/qemu-img.c -index 2f63d31141..2f9e8e77b8 100644 +index edf75e43ab..43f86aa773 100644 --- a/qemu-img.c +++ b/qemu-img.c -@@ -3185,7 +3185,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv) +@@ -3191,7 +3191,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char **argv) list = collect_image_info_list(image_opts, filename, fmt, cache, chain, limits, force_share); if (!list) { diff --git a/debian/patches/pve/0007-PVE-Up-qemu-img-dd-add-osize-and-read-from-to-stdin-.patch b/debian/patches/pve/0007-PVE-Up-qemu-img-dd-add-osize-and-read-from-to-stdin-.patch index 9184458394..355c333078 100644 --- a/debian/patches/pve/0007-PVE-Up-qemu-img-dd-add-osize-and-read-from-to-stdin-.patch +++ b/debian/patches/pve/0007-PVE-Up-qemu-img-dd-add-osize-and-read-from-to-stdin-.patch @@ -55,10 +55,10 @@ index 6bc8265cfb..85458ea2d8 100644 DEF("info", img_info, diff --git a/qemu-img.c b/qemu-img.c -index 2f9e8e77b8..dad04c865e 100644 +index 43f86aa773..82856a38a8 100644 --- a/qemu-img.c +++ b/qemu-img.c -@@ -5320,10 +5320,12 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5326,10 +5326,12 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv) #define C_IF 04 #define C_OF 010 #define C_SKIP 020 @@ -71,7 +71,7 @@ index 2f9e8e77b8..dad04c865e 100644 }; struct DdIo { -@@ -5399,6 +5401,19 @@ static int img_dd_skip(const char *arg, +@@ -5405,6 +5407,19 @@ static int img_dd_skip(const char *arg, return 0; } @@ -91,7 +91,7 @@ index 2f9e8e77b8..dad04c865e 100644 static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) { int ret = 0; -@@ -5439,6 +5454,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5445,6 +5460,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) { "if", img_dd_if, C_IF }, { "of", img_dd_of, C_OF }, { "skip", img_dd_skip, C_SKIP }, @@ -99,7 +99,7 @@ index 2f9e8e77b8..dad04c865e 100644 { NULL, NULL, 0 } }; const struct option long_options[] = { -@@ -5536,91 +5552,112 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5542,91 +5558,112 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) arg = NULL; } @@ -276,7 +276,7 @@ index 2f9e8e77b8..dad04c865e 100644 } if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz || -@@ -5637,20 +5674,43 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5643,20 +5680,43 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) in.buf = g_new(uint8_t, in.bsz); for (out_pos = 0; in_pos < size; ) { diff --git a/debian/patches/pve/0008-PVE-Up-qemu-img-dd-add-isize-parameter.patch b/debian/patches/pve/0008-PVE-Up-qemu-img-dd-add-isize-parameter.patch index db3a1bfaa8..72dbb64ab3 100644 --- a/debian/patches/pve/0008-PVE-Up-qemu-img-dd-add-isize-parameter.patch +++ b/debian/patches/pve/0008-PVE-Up-qemu-img-dd-add-isize-parameter.patch @@ -17,10 +17,10 @@ Signed-off-by: Fiona Ebner 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/qemu-img.c b/qemu-img.c -index dad04c865e..f64a8cb3d3 100644 +index 82856a38a8..eaa143fe48 100644 --- a/qemu-img.c +++ b/qemu-img.c -@@ -5321,11 +5321,13 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5327,11 +5327,13 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv) #define C_OF 010 #define C_SKIP 020 #define C_OSIZE 040 @@ -34,7 +34,7 @@ index dad04c865e..f64a8cb3d3 100644 }; struct DdIo { -@@ -5414,6 +5416,19 @@ static int img_dd_osize(const char *arg, +@@ -5420,6 +5422,19 @@ static int img_dd_osize(const char *arg, return 0; } @@ -54,7 +54,7 @@ index dad04c865e..f64a8cb3d3 100644 static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) { int ret = 0; -@@ -5428,12 +5443,14 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5434,12 +5449,14 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) int c, i; const char *out_fmt = "raw"; const char *fmt = NULL; @@ -70,7 +70,7 @@ index dad04c865e..f64a8cb3d3 100644 }; struct DdIo in = { .bsz = 512, /* Block size is by default 512 bytes */ -@@ -5455,6 +5472,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5461,6 +5478,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) { "of", img_dd_of, C_OF }, { "skip", img_dd_skip, C_SKIP }, { "osize", img_dd_osize, C_OSIZE }, @@ -78,7 +78,7 @@ index dad04c865e..f64a8cb3d3 100644 { NULL, NULL, 0 } }; const struct option long_options[] = { -@@ -5673,9 +5691,10 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5679,9 +5697,10 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) in.buf = g_new(uint8_t, in.bsz); @@ -91,7 +91,7 @@ index dad04c865e..f64a8cb3d3 100644 if (blk1) { in_ret = blk_pread(blk1, in_pos, bytes, in.buf, 0); if (in_ret == 0) { -@@ -5684,6 +5703,9 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5690,6 +5709,9 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) } else { in_ret = read(STDIN_FILENO, in.buf, bytes); if (in_ret == 0) { diff --git a/debian/patches/pve/0009-PVE-Up-qemu-img-dd-add-n-skip_create.patch b/debian/patches/pve/0009-PVE-Up-qemu-img-dd-add-n-skip_create.patch index 5684d3c819..d42e207565 100644 --- a/debian/patches/pve/0009-PVE-Up-qemu-img-dd-add-n-skip_create.patch +++ b/debian/patches/pve/0009-PVE-Up-qemu-img-dd-add-n-skip_create.patch @@ -66,10 +66,10 @@ index 85458ea2d8..f97c2fa396 100644 DEF("info", img_info, diff --git a/qemu-img.c b/qemu-img.c -index f64a8cb3d3..e8e2b0eb68 100644 +index eaa143fe48..25cf0babe4 100644 --- a/qemu-img.c +++ b/qemu-img.c -@@ -5445,7 +5445,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5451,7 +5451,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) const char *fmt = NULL; int64_t size = 0, readsize = 0; int64_t out_pos, in_pos; @@ -78,7 +78,7 @@ index f64a8cb3d3..e8e2b0eb68 100644 struct DdInfo dd = { .flags = 0, .count = 0, -@@ -5485,7 +5485,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5491,7 +5491,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) { 0, 0, 0, 0 } }; @@ -87,7 +87,7 @@ index f64a8cb3d3..e8e2b0eb68 100644 if (c == EOF) { break; } -@@ -5526,6 +5526,9 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5532,6 +5532,9 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) case 'O': out_fmt = optarg; break; @@ -97,7 +97,7 @@ index f64a8cb3d3..e8e2b0eb68 100644 case 'U': force_share = true; break; -@@ -5655,13 +5658,15 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5661,13 +5664,15 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) size - in.bsz * in.offset, &error_abort); } diff --git a/debian/patches/pve/0010-qemu-img-dd-add-l-option-for-loading-a-snapshot.patch b/debian/patches/pve/0010-qemu-img-dd-add-l-option-for-loading-a-snapshot.patch index f3bd76dd6a..00a77964b6 100644 --- a/debian/patches/pve/0010-qemu-img-dd-add-l-option-for-loading-a-snapshot.patch +++ b/debian/patches/pve/0010-qemu-img-dd-add-l-option-for-loading-a-snapshot.patch @@ -48,10 +48,10 @@ index f97c2fa396..206ca7381c 100644 DEF("info", img_info, diff --git a/qemu-img.c b/qemu-img.c -index e8e2b0eb68..8da92a63c0 100644 +index 25cf0babe4..21ec5615e2 100644 --- a/qemu-img.c +++ b/qemu-img.c -@@ -5437,6 +5437,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5443,6 +5443,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) BlockDriver *drv = NULL, *proto_drv = NULL; BlockBackend *blk1 = NULL, *blk2 = NULL; QemuOpts *opts = NULL; @@ -59,7 +59,7 @@ index e8e2b0eb68..8da92a63c0 100644 QemuOptsList *create_opts = NULL; Error *local_err = NULL; bool image_opts = false; -@@ -5446,6 +5447,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5452,6 +5453,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) int64_t size = 0, readsize = 0; int64_t out_pos, in_pos; bool force_share = false, skip_create = false; @@ -67,7 +67,7 @@ index e8e2b0eb68..8da92a63c0 100644 struct DdInfo dd = { .flags = 0, .count = 0, -@@ -5485,7 +5487,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5491,7 +5493,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) { 0, 0, 0, 0 } }; @@ -76,7 +76,7 @@ index e8e2b0eb68..8da92a63c0 100644 if (c == EOF) { break; } -@@ -5529,6 +5531,19 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5535,6 +5537,19 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) case 'n': skip_create = true; break; @@ -96,7 +96,7 @@ index e8e2b0eb68..8da92a63c0 100644 case 'U': force_share = true; break; -@@ -5587,11 +5602,24 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5593,11 +5608,24 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) if (dd.flags & C_IF) { blk1 = img_open(image_opts, in.filename, fmt, 0, false, false, force_share); @@ -122,7 +122,7 @@ index e8e2b0eb68..8da92a63c0 100644 } if (dd.flags & C_OSIZE) { -@@ -5746,6 +5774,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) +@@ -5752,6 +5780,7 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char **argv) out: g_free(arg); qemu_opts_del(opts); diff --git a/debian/patches/pve/0025-PVE-Backup-add-backup-dump-block-driver.patch b/debian/patches/pve/0025-PVE-Backup-add-backup-dump-block-driver.patch index e23026c00b..ba7324d481 100644 --- a/debian/patches/pve/0025-PVE-Backup-add-backup-dump-block-driver.patch +++ b/debian/patches/pve/0025-PVE-Backup-add-backup-dump-block-driver.patch @@ -259,7 +259,7 @@ index 83f858669f..d7ab3cb78f 100644 'blklogwrites.c', 'blkverify.c', diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h -index 147c08155f..41c82fc1ab 100644 +index 46428b034d..94b1dd347d 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -25,6 +25,7 @@ diff --git a/debian/patches/pve/0042-PVE-backup-implement-backup-access-setup-and-teardow.patch b/debian/patches/pve/0042-PVE-backup-implement-backup-access-setup-and-teardow.patch index 598ed3e441..ddd7b1ca3e 100644 --- a/debian/patches/pve/0042-PVE-backup-implement-backup-access-setup-and-teardow.patch +++ b/debian/patches/pve/0042-PVE-backup-implement-backup-access-setup-and-teardow.patch @@ -879,10 +879,10 @@ index 62d7fb4e7a..5e50776664 100644 # @BlockDeviceTimedStats: # diff --git a/system/runstate.c b/system/runstate.c -index 08acf801b0..22306e66bf 100644 +index 3c8693ccf3..b917da82e9 100644 --- a/system/runstate.c +++ b/system/runstate.c -@@ -64,6 +64,7 @@ +@@ -65,6 +65,7 @@ #include "ui/console.h" #include "trace.h" @@ -890,7 +890,7 @@ index 08acf801b0..22306e66bf 100644 static NotifierList exit_notifiers = NOTIFIER_LIST_INITIALIZER(exit_notifiers); -@@ -1036,6 +1037,11 @@ void qemu_cleanup(int status) +@@ -1014,6 +1015,11 @@ void qemu_cleanup(int status) * requests happening from here on anyway. */ bdrv_drain_all_begin(); diff --git a/debian/patches/series b/debian/patches/series index 3140ed6230..fb06234b55 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -2,6 +2,19 @@ extra/0001-monitor-qmp-fix-race-with-clients-disconnecting-earl.patch extra/0002-fdmon-io_uring-avoid-idle-event-loop-being-accounted.patch extra/0003-block-vmdk-tolerate-known-seSparse-reserved1-bit.patch extra/0004-hw-scsi-lsi53c895a-gracefully-handle-re-entrant-DMA.patch +extra/0005-hw-usb-hcd-xhci-Limit-DMA-transfers-to-plain-memory.patch +extra/0006-block-Fix-corruption-from-broken-RMW-atomicity.patch +extra/0007-block-Remove-now-redundant-bdrv_wait_serialising_req.patch +extra/0008-block-fix-bdrv_next-skipping-monitor-owned-nodes.patch +extra/0009-iotests-add-test-cases-for-failing-flush-after-qemu-.patch +extra/0010-iotests.py-add-filter_qemu.patch +extra/0011-block-report-flush-error-during-bdrv_close.patch +extra/0012-qemu-img-convert-flush-target-image-after-copying.patch +extra/0013-qapi-virtio-Restore-backend-features-in-x-query-virt.patch +extra/0014-qapi-monitor-Handle-missing-vhost-user-protocol-feat.patch +extra/0015-system-fix-buffer-overflow-in-tdx_parse_panic_messag.patch +extra/0016-accel-kvm-protect-kvm_resample_fd_list-with-a-mutex.patch +extra/0017-accel-kvm-coalesced-mmio-check-lenght-of-the-MMIO-wr.patch bitmap-mirror/0001-drive-mirror-add-support-for-sync-bitmap-mode-never.patch bitmap-mirror/0002-drive-mirror-add-support-for-conditional-and-always-.patch bitmap-mirror/0003-mirror-add-check-for-bitmap-mode-without-bitmap.patch -- 2.47.3