All of lore.kernel.org
 help / color / mirror / Atom feed
* [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen)
@ 2026-05-22 21:33 Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 58/94] hw/uefi: check auth.hdr_length minimum size Michael Tokarev
                   ` (36 more replies)
  0 siblings, 37 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Michael Tokarev

The following patches are queued for QEMU stable v11.0.1:

  https://gitlab.com/qemu-project/qemu/-/commits/staging-11.0

Patch freeze is 2026-05-22, and the release is planned for 2026-05-24:

  https://wiki.qemu.org/Planning/11.0

Please respond here or CC qemu-stable@nongnu.org on any additional patches
you think should (or shouldn't) be included in the release.

The changes which are staging for inclusion, with the original commit hash
from master branch, are given below the bottom line.

Thanks!

/mjt

--------------------------------------
01* 7437b3eab6af Werner de Carne:
   serial COM: windows serial COM PollingFunc don't sleep
02* 52cf667ed228 GuoHan Zhao:
   ui/spice-app: detect runtime directory creation failures
03* 181fdf8a7e13 Marc-André Lureau:
   ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen)
04* 027ad866bd29 Pierrick Bouvier:
   target/arm/tcg/translate.c: remove MO_TE usage
05* 87e1226e6f68 Marc-André Lureau:
   target/i386: fix strList leak in x86_cpu_get_unavailable_features
06* 3eae91a8b93a Simon Scherer:
   target/i386: fix missing PF_INSTR in SIGSEGV context
07* c906c2337058 rickgcn:
   hw: i386: vapic: restore IRQ polling for non-kernel irqchip backends
08* 7d6231dfb5ea Magnus Kulke:
   target/i386/mshv: Fix segment regression in MMIO emu
09* 76ad26dd172d Paolo Bonzini:
   target/i386/tcg: fix decoding of MOVBE and CRC32 in 16-bit mode
10* 79bc17718677 Stepan Popov:
   meson: add missing semicolon in pthread_condattr_setclock test
11* 7077c83f71a7 Anthony Roberts:
   ui/sdl2: Fix assumption of EGL presence at runtime
12* 30fad722ce68 Alex Bennée:
   hw/display: don't accidentally autofree existing virgl resources
13* d41ce10d0f5a Vladimir Sementsov-Ogievskiy:
   migration: vmstate_save_state_v: fix double error_setg
14* 0990cc8b286b Junjie Cao:
   ati-vga: fix unsigned integer overflow in cursor bounds checks
15* c0306d2b8f45 Thomas Huth:
   hw/misc: Fix the valid access size to the avr-power device
16* 3ab47a47d716 Thomas Huth:
   hw/sh4/sh7750: Remove forgotten abort() in the MM_ITLB_DATA handler
17* 654dce6c5236 Matt Turner:
   linux-user/ppc: Fix ppc64 rt_sigframe stack offset
18* 029f10e85278 Yixin Wei:
   linux-user: fix off-by-one in host_to_target_for_each_rtattr()
19* 93484c768f2b Gyorgy Tamasi:
   linux-user: Don't define target_stat64 struct for loongarch64
20* c8ea1759009a Richard Henderson:
   linux-user/arm/nwfpe: Replace user_registers with current_cpu
21* 784f1dde90df Richard Henderson:
   linux-user/arm/nwfpe: Use thread-local storage for qemufpa
22* 1730e6f33f97 Alistair Francis:
   linux-user/strace: Use pointer type for read and write values
23* 4c681ba3b82d James Hilliard:
   linux-user/mips: sync k0 TLS for EF_MIPS_MACH_OCTEON userlands
24* 8b60ed835478 Helge Deller:
   linux-user: Define SO_TIMESTAMP*_NEW and SO_RCVTIMEIO_NEW
25* edb4588309a7 Helge Deller:
   linux-user: Add setsockopt() for SO_RCVTIMEO_NEW and SO_SNDTIMEO_NEW
26* 07c7decaa54a Helge Deller:
   linux-user: Add getsockopt() for SO_RCVTIMEO_NEW and SO_SNDTIMEO_NEW
27* b03a6ac6fa5d Helge Deller:
   linux-user: Fix CLONE_PARENT_SETTID when using fork-like clone
28* e2af3eadc09b Helge Deller:
   linux-user: Use abi_int for imr_ifindex in ip_mreqn struct
29* 9e7734ead149 Helge Deller:
   linux-user: Flush errors by using exit() instead of _exit() in error path
30* b8c2426157f5 Daniel P. Berrangé:
   util: fix use of pthread_get_name_np on OpenBSD
31* 57abf6b1d576 Luc Michel:
   hw/core/register: add register_array_get_owner
32* 4cb2f91773e8 Yicong Yang:
   hw/riscv/virt-acpi-build.c: Use kvm timer frequency when kvm enabled
33* b2e874bfec59 Sebastián Alba Vives:
   target/riscv: fix stale ptshift and base on page walk restart
34* d5b33fc180f5 Sebastián Alba Vives:
   hw/intc: fix heap OOB in ACLINT MTIMER multi-socket
35* 14808578ccbc Munkhbaatar Enkhbaatar:
   riscv_htif: reject invalid signature ranges (end <= begin)
36* d107b748072c Alistair Francis:
   target/riscv: Generate access fault if sc comparison fails
37* 175afdb0d155 Alistair Francis:
   target/riscv: Don't OR mip.SEIP when mvien is one
38* 5dcc64828dc7 Alistair Francis:
   target/riscv: Use ELEN for Fractional LMUL check
39* dcb6e96257ee Helge Deller:
   linux-user: Add missing CDROM ioctls
40* 9fb681792d65 Helge Deller:
   linux-user: Flush errors by using exit() instead of _exit() in error path
41* 08dc3e240fc0 Helge Deller:
   linux-user: Allow getsockopt() with NULL optval address
42* 9667bf324925 Helge Deller:
   linux-user: Translate errno in IP_RECVERR and IPV6_RECVERR
43* 1aee8067fce9 kiki:
   hw/intc/xics: Add a check for an invalid server id
44* 774e6f5c1533 Vivien LEGER:
   hw/ppc/e500: fix bus-frequency property hardcoded to zero in CPU FDT node
45* a7f27d6903b3 宋文武:
   hw/net/allwinner-sun8i-emac: Flush queued packets when rx is enabled
46* f35f0f1ca121 liugan1:
   hw/intc/arm_gicv3: Fix NS write to ICC_AP1Rn_EL1 when prebits < 7
47* f77a7cec9f64 Fabiano Rosas:
   migration: Use QAPI_CLONE_MEMBERS in migrate_params_test_apply
48* 455a6167f254 Peter Xu:
   migration: Fix low possibility downtime violation
49* 41c417290df9 Philippe Mathieu-Daudé:
   target/microblaze: Fix endianness used to disassemble
50* f443b6876362 Peter Maydell:
   target/arm: Report IL=0 for Thumb 16-bit BKPT insn
51* 18b664c90085 Peter Maydell:
   hw/misc/bcm2835_rng: Specify valid memory access sizes
52* f252769a23e6 Gerd Hoffmann:
   hw/uefi: fix buffer overruns
53* 94d9a8b2c9e6 Gerd Hoffmann:
   hw/uefi: verify pio_xfer_offset before calculating buffer checksum
54* 5247b3034c23 Gerd Hoffmann:
   hw/uefi: fix ucs2 string helper functions
55* c45b460d16f9 Gerd Hoffmann:
   hw/uefi: add name_size check to uefi_vars_mm_lock_variable()
56* 22b7b222d8f5 Gerd Hoffmann:
   hw/uefi: verify data size before accessing it in wrap_pkcs7
57* b4680c02b8e8 Gerd Hoffmann:
   hw/uefi: avoid possibly unaligned variable_auth_2 struct field access
58 b33fd8ab1caa Gerd Hoffmann:
   hw/uefi: check auth.hdr_length minimum size
59* b4ec2e8dae4d Fabiano Rosas:
   tests/functional: Make socat wait longer in migration exec test
60 332ea2978780 Jeuk Kim:
   hw/ufs: Validate MCQ SQ references before use
61 283d921e771e Jeuk Kim:
   hw/ufs: Guard MCQ CQ accesses against missing queues
62 4a909c00b9e1 Jeuk Kim:
   hw/ufs: Reject zero-depth MCQ queues
63 619c2da19a05 Jeuk Kim:
   hw/ufs: Keep MCQ SQs alive while requests are outstanding
64 042dbcff8382 Jeuk Kim:
   hw/ufs: Zero reserved bytes in REPORT LUNS response header
65 aefeecb413a8 Peter Maydell:
   hw/display/cirrus_vga: Fix packed-24 color-expansion transparent pattern 
   fills
66 27d14251b904 Peter Maydell:
   hw/display/cirrus_vga: Fix packed-24 color-expansion transparent copies
67 ff36712da5ae Kane Chen:
   hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
68 534a52755bef Cédric Le Goater:
   aspeed/hace: Fix out-of-bounds read in has_padding()
69 c6aa2d0ac161 Cédric Le Goater:
   aspeed/hace: Prevent total_req_len overflow
70 a824f3531a44 Peter Maydell:
   hw/i2c/microbit_i2c: Don't index off end of twi_read_sequence[]
71 6197c11dd5d2 Chad Jablonski:
   ati-vga: fix ati_set_dirty address calculation
72 0129c626503c Peter Maydell:
   tests/qtest/iommu-smmuv3-test: Skip if no TCG GICv3 device present
73 a163fc1f864b Peter Maydell:
   meson.build: Add -fzero-init-padding-bits=all
74 4e8ac6857faa Peter Maydell:
   hw/remote/machine.c: Mark x-remote machine as OK for AArch64 and AArch32
75 039b057c09c6 Peter Maydell:
   tests/functional/qemu_test/asset.py: Don't use setxattr when it doesn't 
   exist
76 a86024eb2df5 Scott J. Goldman:
   target/arm/hvf: Fix WFI halting to stop idle vCPU spinning
77 2293d8b4bd88 Klaus Jensen:
   hw/nvme: fix admin cq msix setup
78 6b5aef7cac9d Helge Deller:
   linux-user: Fix AT_EXECFN in AUXV for symlinked programs
79 c3176e645774 Matt Turner:
   linux-user/sh4: Fix target_ucontext tuc_link field type
80 9ac5aa722721 Matt Turner:
   linux-user/sh4: Fix setup_sigtramp to match Linux kernel trampoline 
   pattern
81 d5e4090177ad Kevin Wolf:
   blkdebug: Add 'delay-ns' option
82 34a67637767d Kevin Wolf:
   block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE
83 53074ba0330a Kevin Wolf:
   block: Add flags parameter to blk_*_pdiscard()
84 095c08a7ba68 Kevin Wolf:
   ide: Minimal fix for deadlock between TRIM and drain
85 c1c71a7e167f Kevin Wolf:
   ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code
86 92854c9c7539 Kevin Wolf:
   ide-test: Factor out wait_dma_completion()
87 2fa24e975599 Kevin Wolf:
   ide-test: Test reset during TRIM
88 a1310cc6281d Kevin Wolf:
   block: Create DEFAULT_BLOCK_CONF macro
89 f27aea189633 Kevin Wolf:
   block: Add more defaults to DEFAULT_BLOCK_CONF
90 f0d9ccd46cf8 Kevin Wolf:
   commit: Drain nodes across all of bdrv_commit()
91 7f8466e2ce62 Kevin Wolf:
   qemu-io: Add 'aio_discard' command
92 b8bfb1478d61 Kevin Wolf:
   qcow2: Fix corruption on discard during write with COW
93 389f5bcc744d Kevin Wolf:
   iotests/046: Test that discard/write_zeroes wait for dependencies
94 e3082ab3b385 Denis V. Lunev:
   block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock()

(commit(s) marked with * were in previous series and are not resent)


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 58/94] hw/uefi: check auth.hdr_length minimum size
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 60/94] hw/ufs: Validate MCQ SQ references before use Michael Tokarev
                   ` (35 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Gerd Hoffmann, Feifan Qian, Daniel P. Berrangé,
	Michael Tokarev

From: Gerd Hoffmann <kraxel@redhat.com>

auth.hdr_length maximum is already checked (against buffer size).  The
header has some fixed fields which are included in the header length, so
there also is a minimum size which must be verified.  Add a check for
that.  Fixes possible integer underflow.

While being at it replace the magic number '24' with sizeof calculations
for better code documentation.

Fixes: CVE-2026-8341
Fixes: f1488fac0584 ("hw/uefi: add var-service-auth.c")
Reported-by: Feifan Qian <bea1e@proton.me>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-ID: <20260512060523.17493-1-kraxel@redhat.com>
(cherry picked from commit b33fd8ab1caa07aeb290ef5dac44a4e7fd4be02b)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/uefi/var-service-auth.c b/hw/uefi/var-service-auth.c
index 795f2f54e4..f3dc9c6ca6 100644
--- a/hw/uefi/var-service-auth.c
+++ b/hw/uefi/var-service-auth.c
@@ -194,7 +194,7 @@ static efi_status uefi_vars_check_auth_2_sb(uefi_vars_state *uv,
         return EFI_SUCCESS;
     }
 
-    if (auth.hdr_length == 24) {
+    if (auth.hdr_length == (sizeof(auth) - sizeof(auth.timestamp))) {
         /* no signature (auth->cert_data is empty) */
         return EFI_SECURITY_VIOLATION;
     }
@@ -228,6 +228,9 @@ efi_status uefi_vars_check_auth_2(uefi_vars_state *uv, uefi_variable *var,
     }
     memcpy(&auth, data, sizeof(auth));
 
+    if (auth.hdr_length < (sizeof(auth) - sizeof(auth.timestamp))) {
+        return EFI_SECURITY_VIOLATION;
+    }
     if (uadd64_overflow(sizeof(efi_time), auth.hdr_length, &data_offset)) {
         return EFI_SECURITY_VIOLATION;
     }
diff --git a/hw/uefi/var-service-pkcs7.c b/hw/uefi/var-service-pkcs7.c
index c859743e86..8a1f1395a2 100644
--- a/hw/uefi/var-service-pkcs7.c
+++ b/hw/uefi/var-service-pkcs7.c
@@ -113,9 +113,9 @@ static gnutls_datum_t *build_pkcs7(void *data)
 
     memcpy(&auth, data, sizeof(auth));
     pkcs7 = g_new(gnutls_datum_t, 1);
-    pkcs7->size = auth.hdr_length - 24;
+    pkcs7->size = auth.hdr_length - (sizeof(auth) - sizeof(auth.timestamp));
     pkcs7->data = g_malloc(pkcs7->size);
-    memcpy(pkcs7->data, data + 16 + 24, pkcs7->size);
+    memcpy(pkcs7->data, data + sizeof(auth), pkcs7->size);
 
     wrap_pkcs7(pkcs7);
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 60/94] hw/ufs: Validate MCQ SQ references before use
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 58/94] hw/uefi: check auth.hdr_length minimum size Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 61/94] hw/ufs: Guard MCQ CQ accesses against missing queues Michael Tokarev
                   ` (34 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Jeuk Kim, Rayhan Ramdhany Hanaputra, Michael Tokarev

From: Jeuk Kim <jeuk20.kim@samsung.com>

A guest can program an out-of-range SQATTR.CQID value, or ring an
MCQ SQ doorbell before the submission queue exists.

Reject SQ creation when the referenced CQ is invalid, and ignore SQ
doorbells for queues that have not been created. This prevents a
guest-triggerable out-of-bounds read and NULL pointer dereference.

Fixes: 5c079578d2e ("hw/ufs: Add support MCQ of UFSHCI 4.0")
Reported-by: Rayhan Ramdhany Hanaputra <hanaputrarayhan@gmail.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
(cherry picked from commit 332ea29787800fff2b49e9b89ec93bd370a11965)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index cb74cb56bc..d5fba15e2a 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -517,8 +517,13 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid, uint32_t attr)
         return false;
     }
 
+    if (cqid >= u->params.mcq_maxq) {
+        trace_ufs_err_mcq_create_sq_invalid_cqid(cqid);
+        return false;
+    }
+
     if (!u->cq[cqid]) {
-        trace_ufs_err_mcq_create_sq_invalid_cqid(qid);
+        trace_ufs_err_mcq_create_sq_invalid_cqid(cqid);
         return false;
     }
 
@@ -775,6 +780,11 @@ static void ufs_mcq_process_db(UfsHc *u, uint8_t qid, uint32_t db)
     }
 
     sq = u->sq[qid];
+    if (!sq) {
+        trace_ufs_err_mcq_db_wr_invalid_sqid(qid);
+        return;
+    }
+
     if (sq->size * sizeof(UfsSqEntry) <= db) {
         trace_ufs_err_mcq_db_wr_invalid_db(qid, db);
         return;
@@ -788,7 +798,14 @@ static void ufs_write_mcq_op_reg(UfsHc *u, hwaddr offset, uint32_t data,
                                  unsigned size)
 {
     int qid = offset / sizeof(UfsMcqOpReg);
-    UfsMcqOpReg *opr = &u->mcq_op_reg[qid];
+    UfsMcqOpReg *opr;
+
+    if (qid >= u->params.mcq_maxq) {
+        trace_ufs_err_invalid_register_offset(offset);
+        return;
+    }
+
+    opr = &u->mcq_op_reg[qid];
 
     switch (offset % sizeof(UfsMcqOpReg)) {
     case offsetof(UfsMcqOpReg, sq.tp):
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 61/94] hw/ufs: Guard MCQ CQ accesses against missing queues
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 58/94] hw/uefi: check auth.hdr_length minimum size Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 60/94] hw/ufs: Validate MCQ SQ references before use Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 62/94] hw/ufs: Reject zero-depth MCQ queues Michael Tokarev
                   ` (33 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Jeuk Kim, Rayhan Ramdhany Hanaputra, Michael Tokarev

From: Jeuk Kim <jeuk20.kim@samsung.com>

A guest can ring an MCQ CQ doorbell before the completion queue exists.
The CQ head write path then dereferences a NULL CQ through
ufs_mcq_cq_full().

Ignore CQ head updates for missing CQs, and make ufs_mcq_cq_full()
handle a missing CQ defensively.

Fixes: f78762a3cc8 ("hw/ufs: Fix mcq completion queue wraparound")
Reported-by: Rayhan Ramdhany Hanaputra <hanaputrarayhan@gmail.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
(cherry picked from commit 283d921e771e8a98a5c3d1eed1ed791b89ba47a8)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index d5fba15e2a..1819ba2e8a 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -817,6 +817,10 @@ static void ufs_write_mcq_op_reg(UfsHc *u, hwaddr offset, uint32_t data,
     case offsetof(UfsMcqOpReg, cq.hp): {
         UfsCq *cq = u->cq[qid];
 
+        if (!cq) {
+            break;
+        }
+
         if (ufs_mcq_cq_full(u, qid) && !QTAILQ_EMPTY(&cq->req_list)) {
             /* Enqueueing to CQ was blocked because it was full */
             qemu_bh_schedule(cq->bh);
diff --git a/hw/ufs/ufs.h b/hw/ufs/ufs.h
index 13d964c5ae..9e800cafac 100644
--- a/hw/ufs/ufs.h
+++ b/hw/ufs/ufs.h
@@ -203,7 +203,14 @@ static inline bool ufs_mcq_cq_empty(UfsHc *u, uint32_t qid)
 static inline bool ufs_mcq_cq_full(UfsHc *u, uint32_t qid)
 {
     uint32_t tail = ufs_mcq_cq_tail(u, qid);
-    uint16_t cq_size = u->cq[qid]->size;
+    UfsCq *cq = u->cq[qid];
+    uint16_t cq_size;
+
+    if (!cq) {
+        return false;
+    }
+
+    cq_size = cq->size;
 
     tail = (tail + sizeof(UfsCqEntry)) % (sizeof(UfsCqEntry) * cq_size);
     return tail == ufs_mcq_cq_head(u, qid);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 62/94] hw/ufs: Reject zero-depth MCQ queues
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (2 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 61/94] hw/ufs: Guard MCQ CQ accesses against missing queues Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 63/94] hw/ufs: Keep MCQ SQs alive while requests are outstanding Michael Tokarev
                   ` (32 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Jeuk Kim, Michael Tokarev

From: Jeuk Kim <jeuk20.kim@samsung.com>

Reject SQATTR.SIZE and CQATTR.SIZE values that produce zero-entry MCQ
queues. Such queues can later trigger a divide-by-zero while advancing
queue pointers.

Fixes: 5c079578d2e ("hw/ufs: Add support MCQ of UFSHCI 4.0")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
(cherry picked from commit 4a909c00b9e18478e67a792c7f7cfae62cb6c865)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
index 531dcfc686..7734b35f08 100644
--- a/hw/ufs/trace-events
+++ b/hw/ufs/trace-events
@@ -40,10 +40,12 @@ ufs_err_mcq_db_wr_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
 ufs_err_mcq_db_wr_invalid_db(uint8_t qid, uint32_t db) "invalid mcq doorbell sqid %"PRIu8", db %"PRIu32""
 ufs_err_mcq_create_sq_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
 ufs_err_mcq_create_sq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
+ufs_err_mcq_create_sq_invalid_size(uint8_t qid) "invalid mcq sq size for sqid %"PRIu8""
 ufs_err_mcq_create_sq_already_exists(uint8_t qid) "mcq sqid %"PRIu8 "already exists"
 ufs_err_mcq_delete_sq_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
 ufs_err_mcq_delete_sq_not_exists(uint8_t qid) "mcq sqid %"PRIu8 "not exists"
 ufs_err_mcq_create_cq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
+ufs_err_mcq_create_cq_invalid_size(uint8_t qid) "invalid mcq cq size for cqid %"PRIu8""
 ufs_err_mcq_create_cq_already_exists(uint8_t qid) "mcq cqid %"PRIu8 "already exists"
 ufs_err_mcq_delete_cq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
 ufs_err_mcq_delete_cq_not_exists(uint8_t qid) "mcq cqid %"PRIu8 "not exists"
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 1819ba2e8a..4ccd7aa64d 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -506,6 +506,8 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid, uint32_t attr)
     UfsMcqReg *reg = &u->mcq_reg[qid];
     UfsSq *sq;
     uint8_t cqid = FIELD_EX32(attr, SQATTR, CQID);
+    uint16_t qsize =
+        ((FIELD_EX32(attr, SQATTR, SIZE) + 1) << 2) / sizeof(UfsSqEntry);
 
     if (qid >= u->params.mcq_maxq) {
         trace_ufs_err_mcq_create_sq_invalid_sqid(qid);
@@ -527,12 +529,17 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid, uint32_t attr)
         return false;
     }
 
+    if (!qsize) {
+        trace_ufs_err_mcq_create_sq_invalid_size(qid);
+        return false;
+    }
+
     sq = g_malloc0(sizeof(*sq));
     sq->u = u;
     sq->sqid = qid;
     sq->cq = u->cq[cqid];
     sq->addr = ((uint64_t)reg->squba << 32) | reg->sqlba;
-    sq->size = ((FIELD_EX32(attr, SQATTR, SIZE) + 1) << 2) / sizeof(UfsSqEntry);
+    sq->size = qsize;
 
     sq->bh = qemu_bh_new_guarded(ufs_mcq_process_sq, sq,
                                  &DEVICE(u)->mem_reentrancy_guard);
@@ -576,6 +583,8 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid, uint32_t attr)
 {
     UfsMcqReg *reg = &u->mcq_reg[qid];
     UfsCq *cq;
+    uint16_t qsize =
+        ((FIELD_EX32(attr, CQATTR, SIZE) + 1) << 2) / sizeof(UfsCqEntry);
 
     if (qid >= u->params.mcq_maxq) {
         trace_ufs_err_mcq_create_cq_invalid_cqid(qid);
@@ -587,11 +596,16 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid, uint32_t attr)
         return false;
     }
 
+    if (!qsize) {
+        trace_ufs_err_mcq_create_cq_invalid_size(qid);
+        return false;
+    }
+
     cq = g_malloc0(sizeof(*cq));
     cq->u = u;
     cq->cqid = qid;
     cq->addr = ((uint64_t)reg->cquba << 32) | reg->cqlba;
-    cq->size = ((FIELD_EX32(attr, CQATTR, SIZE) + 1) << 2) / sizeof(UfsCqEntry);
+    cq->size = qsize;
 
     cq->bh = qemu_bh_new_guarded(ufs_mcq_process_cq, cq,
                                  &DEVICE(u)->mem_reentrancy_guard);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 63/94] hw/ufs: Keep MCQ SQs alive while requests are outstanding
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (3 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 62/94] hw/ufs: Reject zero-depth MCQ queues Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 64/94] hw/ufs: Zero reserved bytes in REPORT LUNS response header Michael Tokarev
                   ` (31 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Jeuk Kim, Michael Tokarev

From: Jeuk Kim <jeuk20.kim@samsung.com>

MCQ requests are allocated with their SQ, but can remain in flight on the
CQ list or in the SCSI layer after leaving the SQ free list.

Reject runtime SQ deletion while any request is still outstanding, and
use separate teardown helpers so device exit can still release MCQ
queues after child devices have been unrealized.

Fixes: 5c079578d2e ("hw/ufs: Add support MCQ of UFSHCI 4.0")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
(cherry picked from commit 619c2da19a05668dabe7912afb789e50b8635c4d)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/ufs/trace-events b/hw/ufs/trace-events
index 7734b35f08..6f7ea9c95f 100644
--- a/hw/ufs/trace-events
+++ b/hw/ufs/trace-events
@@ -44,6 +44,7 @@ ufs_err_mcq_create_sq_invalid_size(uint8_t qid) "invalid mcq sq size for sqid %"
 ufs_err_mcq_create_sq_already_exists(uint8_t qid) "mcq sqid %"PRIu8 "already exists"
 ufs_err_mcq_delete_sq_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
 ufs_err_mcq_delete_sq_not_exists(uint8_t qid) "mcq sqid %"PRIu8 "not exists"
+ufs_err_mcq_delete_sq_busy(uint8_t qid) "mcq sqid %"PRIu8" has outstanding requests"
 ufs_err_mcq_create_cq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
 ufs_err_mcq_create_cq_invalid_size(uint8_t qid) "invalid mcq cq size for cqid %"PRIu8""
 ufs_err_mcq_create_cq_already_exists(uint8_t qid) "mcq cqid %"PRIu8 "already exists"
diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c
index 4ccd7aa64d..6548f0f637 100644
--- a/hw/ufs/ufs.c
+++ b/hw/ufs/ufs.c
@@ -556,6 +556,31 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid, uint32_t attr)
     return true;
 }
 
+static bool ufs_mcq_sq_has_outstanding_req(UfsSq *sq)
+{
+    UfsRequest *req;
+    uint16_t free_reqs = 0;
+
+    QTAILQ_FOREACH(req, &sq->req_list, entry)
+    {
+        free_reqs++;
+    }
+
+    return free_reqs != sq->size;
+}
+
+static void ufs_mcq_free_sq(UfsSq *sq)
+{
+    qemu_bh_delete(sq->bh);
+
+    for (int i = 0; i < sq->size; i++) {
+        ufs_clear_req(&sq->req[i]);
+    }
+
+    g_free(sq->req);
+    g_free(sq);
+}
+
 static bool ufs_mcq_delete_sq(UfsHc *u, uint8_t qid)
 {
     UfsSq *sq;
@@ -572,9 +597,12 @@ static bool ufs_mcq_delete_sq(UfsHc *u, uint8_t qid)
 
     sq = u->sq[qid];
 
-    qemu_bh_delete(sq->bh);
-    g_free(sq->req);
-    g_free(sq);
+    if (ufs_mcq_sq_has_outstanding_req(sq)) {
+        trace_ufs_err_mcq_delete_sq_busy(qid);
+        return false;
+    }
+
+    ufs_mcq_free_sq(sq);
     u->sq[qid] = NULL;
     return true;
 }
@@ -617,6 +645,12 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid, uint32_t attr)
     return true;
 }
 
+static void ufs_mcq_free_cq(UfsCq *cq)
+{
+    qemu_bh_delete(cq->bh);
+    g_free(cq);
+}
+
 static bool ufs_mcq_delete_cq(UfsHc *u, uint8_t qid)
 {
     UfsCq *cq;
@@ -640,8 +674,7 @@ static bool ufs_mcq_delete_cq(UfsHc *u, uint8_t qid)
 
     cq = u->cq[qid];
 
-    qemu_bh_delete(cq->bh);
-    g_free(cq);
+    ufs_mcq_free_cq(cq);
     u->cq[qid] = NULL;
     return true;
 }
@@ -1884,12 +1917,14 @@ static void ufs_exit(PCIDevice *pci_dev)
 
     for (int i = 0; i < ARRAY_SIZE(u->sq); i++) {
         if (u->sq[i]) {
-            ufs_mcq_delete_sq(u, i);
+            ufs_mcq_free_sq(u->sq[i]);
+            u->sq[i] = NULL;
         }
     }
     for (int i = 0; i < ARRAY_SIZE(u->cq); i++) {
         if (u->cq[i]) {
-            ufs_mcq_delete_cq(u, i);
+            ufs_mcq_free_cq(u->cq[i]);
+            u->cq[i] = NULL;
         }
     }
 }
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 64/94] hw/ufs: Zero reserved bytes in REPORT LUNS response header
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (4 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 63/94] hw/ufs: Keep MCQ SQs alive while requests are outstanding Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 65/94] hw/display/cirrus_vga: Fix packed-24 color-expansion transparent pattern fills Michael Tokarev
                   ` (30 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Jeuk Kim, Michael Tokarev

From: Jeuk Kim <jeuk20.kim@samsung.com>

ufs_emulate_report_luns() writes the 4-byte LUN list length into
outbuf[0..3] via stl_be_p() but leaves outbuf[4..7], the reserved
field, uninitialized. Those bytes are then DMA'd to guest memory,
leaking uninitialized QEMU stack data.

Fixes: 7708e298180 ("hw/ufs/lu: skip automatic zero-init of large array")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>
(cherry picked from commit 042dbcff8382393b20b716294a6c4b1a4af6b3f1)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c
index 3f3c9589ce..709d6adcf6 100644
--- a/hw/ufs/lu.c
+++ b/hw/ufs/lu.c
@@ -101,6 +101,10 @@ static int ufs_emulate_report_luns(UfsRequest *req, uint8_t *outbuf,
         return SCSI_COMMAND_FAIL;
     }
 
+    if (outbuf_len < 8) {
+        return SCSI_COMMAND_FAIL;
+    }
+    memset(outbuf, 0, 8);
     len += 8;
 
     for (uint8_t lun = 0; lun < UFS_MAX_LUS; ++lun) {
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 65/94] hw/display/cirrus_vga: Fix packed-24 color-expansion transparent pattern fills
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (5 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 64/94] hw/ufs: Zero reserved bytes in REPORT LUNS response header Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 66/94] hw/display/cirrus_vga: Fix packed-24 color-expansion transparent copies Michael Tokarev
                   ` (29 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Peter Maydell, Junjie Cao,
	Philippe Mathieu-Daudé, Michael Tokarev

From: Peter Maydell <peter.maydell@linaro.org>

The Cirrus Logic VGA card has "pattern fill" blit modes where it
repeatedly copies an 8x8 source pattern to the display.  For the
"color expansion" subtype of these, the source pixel format is an 8x8
monochrome bitmap, and the destination can be any of 8, 16, 24 or
32bpp.  We implemented these wrong for the 24bpp case, in a way that
results in a complaint from the undefined-behavior sanitizer about a
shift by a negative value.

For these pattern fills, the GR2F register includes a field which
specifies how much to skip at the start of each scanline.  In the 8,
16 and 32 bit cases, this field is 3 bits and is a count of pixels to
skip.  We get this case right.  However, for the 24 bit case, the
field is 5 bits and is a count of destination bytes to skip.  We
tried to add support for 24-bits in commit ad81218e40e27 ("depth=24
write mask fix (Volker Ruppert)") in 2005.  However we got this
wrong, because when we need to skip, for example, 30 bytes in the
destination, this is 10 input pixels but the whole pattern is only 8
pixels wide, and we ended up with a negative bitpos for the first bit
to use in the pattern.

Fix the bug by masking srcskipleft in the 24-bit case so that it
correctly gives the first pixel to use in the pattern even if we skip
so many pixels that we have wrapped around to what would have been
the second copy of the pattern to the destination.

This patch was produced based on the information in the CL-GD5446
Technical Reference Manual, specifically sections 5.8 "GR2F: BLT
Destination Left-Side Clipping" and 9.4.8 "Pattern Fills".

Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3377
Fixes: ad81218e40e27 ("depth=24 write mask fix (Volker Ruppert)")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Junjie Cao <junjie.cao@intel.com>
Tested-by: Junjie Cao <junjie.cao@intel.com>
Message-ID: <20260410183249.4046456-2-peter.maydell@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit aefeecb413a8e404ecb6d210cc32d60da176a336)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/display/cirrus_vga_rop2.h b/hw/display/cirrus_vga_rop2.h
index b208b7348a..8be35ec6e2 100644
--- a/hw/display/cirrus_vga_rop2.h
+++ b/hw/display/cirrus_vga_rop2.h
@@ -191,10 +191,29 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
     int x, y, bitpos, pattern_y;
     unsigned int bits, bits_xor;
     unsigned int col;
+
+    /*
+     * Copy from an 8x8 monochrome pattern with color expansion.
+     */
+
 #if DEPTH == 24
+    /*
+     * For packed-24 modes, GR2F bits [4:0] are a count of destination
+     * bytes to be suppressed for each scanline, which we keep in
+     * dstskipleft. Our srcskipleft is the number of pixels to skip
+     * within the 8x8 source pattern to match up with that number
+     * of suppressed bytes. As the pattern repeats every 8 bits we
+     * take the number of pixels mod 8.
+     */
     int dstskipleft = s->vga.gr[0x2f] & 0x1f;
-    int srcskipleft = dstskipleft / 3;
+    int srcskipleft = (dstskipleft / 3) & 0x7;
 #else
+    /*
+     * In all other modes, GR2F bits [2:0] are a count of how many
+     * destination pixels to suppress for each scanline, which is our
+     * srcskipleft. We get dstskipleft, the number of bytes to skip,
+     * by multiplying this by the bytes-per-pixel.
+     */
     int srcskipleft = s->vga.gr[0x2f] & 0x07;
     int dstskipleft = srcskipleft * (DEPTH / 8);
 #endif
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 66/94] hw/display/cirrus_vga: Fix packed-24 color-expansion transparent copies
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (6 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 65/94] hw/display/cirrus_vga: Fix packed-24 color-expansion transparent pattern fills Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 67/94] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations Michael Tokarev
                   ` (28 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Peter Maydell, Junjie Cao,
	Philippe Mathieu-Daudé, Michael Tokarev

From: Peter Maydell <peter.maydell@linaro.org>

For the "color expansion" subtype of raster operations, the source
pixel format is a monochrome bitmap, and the destination can be any
of 8, 16, 24 or 32bpp.

For these pattern operations, the GR2F register includes a field
which specifies how much to skip at the start of each scanline.  In
the 8, 16 and 32 bit cases, this field is 3 bits and is a count of
pixels to skip.  We get this case right.  However, for the 24 bit
case, the field is 5 bits and is a count of destination bytes to
skip.

In commit ad81218e40e27 ("depth=24 write mask fix (Volker Ruppert)")
in 2005, we updated the code to (attempt to) handle the 5-bit mask
case.  However, we don't do the right thing when the 5-bit mask
indicates that we need to skip more than 8 bits of the input bitmap:
we will right-shift the 0x80 constant completely off the right hand
side, and will be off-by-one for all the source bitmap loads.

Fix this by calculating the whole number of input bytes we need to
skip and the residual number of bits.  In the 8/16/32bpp case the
bytes to skip is always zero.

Cc: qemu-stable@nongnu.org
Fixes: ad81218e40e27 ("depth=24 write mask fix (Volker Ruppert)")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Junjie Cao <junjie.cao@intel.com>
Tested-by: Junjie Cao <junjie.cao@intel.com>
Message-ID: <20260410183249.4046456-3-peter.maydell@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 27d14251b904e6dd60c1053a893b52e085f48a3a)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/display/cirrus_vga_rop2.h b/hw/display/cirrus_vga_rop2.h
index 8be35ec6e2..33f9b3b613 100644
--- a/hw/display/cirrus_vga_rop2.h
+++ b/hw/display/cirrus_vga_rop2.h
@@ -108,12 +108,34 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
     unsigned int col;
     unsigned bitmask;
     unsigned index;
+
+    /*
+     * Raster ops where the source is a monochrome bitmap with
+     * color expansion to 8/16/24/32bpp destination.
+     */
+
 #if DEPTH == 24
+    /*
+     * For packed-24 modes, GR2F bits [4:0] are a count of destination
+     * bytes to be suppressed for each scanline, which we keep in
+     * dstskipleft. We want to track the number of whole bytes
+     * to skip in the source (always either 0 or 1) and the number
+     * of bits within the byte to skip.
+     */
     int dstskipleft = s->vga.gr[0x2f] & 0x1f;
-    int srcskipleft = dstskipleft / 3;
+    int srcskipleftbits = (dstskipleft / 3) & 0x7;
+    int srcskipleftbytes = (dstskipleft / 3) >> 3;
 #else
-    int srcskipleft = s->vga.gr[0x2f] & 0x07;
-    int dstskipleft = srcskipleft * (DEPTH / 8);
+    /*
+     * In all other modes, GR2F bits [2:0] are a count of how many
+     * destination pixels to suppress for each scanline, which is our
+     * srcskipleftbits. We get dstskipleft, the number of bytes to
+     * skip, by multiplying this by the bytes-per-pixel. In these
+     * modes we never need to skip an entire source byte.
+     */
+    int srcskipleftbits = s->vga.gr[0x2f] & 0x07;
+    int srcskipleftbytes = 0;
+    int dstskipleft = srcskipleftbits * (DEPTH / 8);
 #endif
 
     if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
@@ -125,7 +147,8 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
     }
 
     for(y = 0; y < bltheight; y++) {
-        bitmask = 0x80 >> srcskipleft;
+        bitmask = 0x80 >> srcskipleftbits;
+        srcaddr += srcskipleftbytes;
         bits = cirrus_src(s, srcaddr++) ^ bits_xor;
         addr = dstaddr + dstskipleft;
         for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 67/94] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (7 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 66/94] hw/display/cirrus_vga: Fix packed-24 color-expansion transparent copies Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 68/94] aspeed/hace: Fix out-of-bounds read in has_padding() Michael Tokarev
                   ` (27 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Kane Chen, Peter Maydell, Cédric Le Goater,
	Michael Tokarev

From: Kane Chen <kane_chen@aspeedtech.com>

There is a mismatch between the Aspeed OTP model and the Aspeed SBC
model in how the guest-provided address is handled.
aspeed_sbc_otp_prog() passes a word-indexed address directly
to address_space_write() without converting it to a byte offset,
whereas aspeed_otp_write() expects a byte offset and applies an
additional shift (otp_addr << 2). This double-shift confusion means
that an out-of-range word address can lead to a write beyond the
allocated storage.

Fix this by adding bounds checking on the word offset before
converting to byte offset and passing to address_space_write().
This matches the existing bounds check in aspeed_sbc_otp_read().

Cc: Kane-Chen-AS <kane_chen@aspeedtech.com>
Cc: qemu-stable@nongnu.org
Fixes: 1a00754ccf15 ("hw/misc: Add Aspeed Secure Boot Controller model")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3436
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Kane-Chen-AS <kane_chen@aspeedtech.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Link: https://lore.kernel.org/qemu-devel/20260428055254.76581-2-kane_chen@aspeedtech.com
[ clg: Kept otp_addr in event logged in aspeed_sbc_otp_prog() ]
Signed-off-by: Cédric Le Goater <clg@redhat.com>
(cherry picked from commit ff36712da5ae73aca5a044fe5e61c585d427013a)
(Mjt: actual Fixes: tag is this one)
Fixes: 9f58dd0a8c30 ("hw/misc/aspeed_sbc: Connect ASPEED OTP memory device to SBC")
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c
index 065e822e70..e5dab1c7bb 100644
--- a/hw/misc/aspeed_sbc.c
+++ b/hw/misc/aspeed_sbc.c
@@ -159,9 +159,17 @@ static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
     MemTxResult ret;
     AspeedOTPState *otp = &s->otp;
     uint32_t value = s->regs[R_CAMP1];
+    uint32_t otp_offset = otp_addr << 2;
 
-    ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
-                        &value, sizeof(value));
+    if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "Invalid OTP addr 0x%x\n",
+                      otp_addr);
+        return false;
+    }
+
+    ret = address_space_write(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
+                              &value, sizeof(value));
     if (ret != MEMTX_OK) {
         qemu_log_mask(LOG_GUEST_ERROR,
                       "Failed to write OTP memory, addr = %x\n",
diff --git a/hw/nvram/aspeed_otp.c b/hw/nvram/aspeed_otp.c
index a60289000c..1a9d3841b8 100644
--- a/hw/nvram/aspeed_otp.c
+++ b/hw/nvram/aspeed_otp.c
@@ -57,12 +57,12 @@ static bool valid_program_data(uint32_t otp_addr,
     return has_programmable_bits != 0;
 }
 
-static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
+static bool program_otpmem_data(void *opaque, hwaddr otp_offset,
                              uint32_t prog_bit, uint32_t *value)
 {
     AspeedOTPState *s = opaque;
+    uint32_t otp_addr = otp_offset >> 2;
     bool is_odd = otp_addr & 1;
-    uint32_t otp_offset = otp_addr << 2;
 
     memcpy(value, s->storage + otp_offset, sizeof(uint32_t));
 
@@ -79,26 +79,25 @@ static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
     return true;
 }
 
-static void aspeed_otp_write(void *opaque, hwaddr otp_addr,
+static void aspeed_otp_write(void *opaque, hwaddr otp_offset,
                                 uint64_t val, unsigned size)
 {
     AspeedOTPState *s = opaque;
-    uint32_t otp_offset, value;
+    uint32_t value;
 
-    if (!program_otpmem_data(s, otp_addr, val, &value)) {
+    if (!program_otpmem_data(s, otp_offset, val, &value)) {
         qemu_log_mask(LOG_GUEST_ERROR,
                       "%s: Failed to program data, value = %x, bit = %"PRIx64"\n",
                       __func__, value, val);
         return;
     }
 
-    otp_offset = otp_addr << 2;
     memcpy(s->storage + otp_offset, &value, size);
 
     if (s->blk) {
         if (blk_pwrite(s->blk, otp_offset, size, &value, 0) < 0) {
             qemu_log_mask(LOG_GUEST_ERROR,
-                          "%s: Failed to write %x to %x\n",
+                          "%s: Failed to write %x to %"HWADDR_PRIx"\n",
                           __func__, value, otp_offset);
 
             return;
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 68/94] aspeed/hace: Fix out-of-bounds read in has_padding()
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (8 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 67/94] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 69/94] aspeed/hace: Prevent total_req_len overflow Michael Tokarev
                   ` (26 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Cédric Le Goater, Katherine Leaver,
	Michael Tokarev

From: Cédric Le Goater <clg@redhat.com>

The has_padding() function reads the last 8 bytes of a DMA buffer
without validating req_len. req_len is guest-controlled (via
R_HASH_SRC_LEN register or scatter-gather entries) and values less
than 8 cause integer underflow. This can result in an out-of-bounds
read of QEMU process memory.

Add a check to ensure req_len >= 8 before accessing the buffer.

Reported-by: Katherine Leaver <katherine.j.leaver@gmail.com>
Cc: qemu-stable@nongnu.org
Fixes: 5cd7d8564a8b ("aspeed/hace: Support AST2600 HACE")
Link: https://lore.kernel.org/qemu-devel/20260504213421.710035-2-clg@redhat.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
(cherry picked from commit 534a52755befa7b8d49c921f8dc964185903efae)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c
index 23e8030cd9..ef698b3ecb 100644
--- a/hw/misc/aspeed_hace.c
+++ b/hw/misc/aspeed_hace.c
@@ -154,6 +154,14 @@ static bool has_padding(AspeedHACEState *s, struct iovec *iov,
                         hwaddr req_len, uint32_t *total_msg_len,
                         uint32_t *pad_offset)
 {
+    /* Need at least 8 bytes to read the total message length field */
+    if (req_len < 8) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: invalid request length=0x%" HWADDR_PRIx "\n",
+                      __func__, req_len);
+        return false;
+    }
+
     *total_msg_len = (uint32_t)(ldq_be_p(iov->iov_base + req_len - 8) / 8);
     /*
      * SG_LIST_LEN_LAST asserted in the request length doesn't mean it is the
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 69/94] aspeed/hace: Prevent total_req_len overflow
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (9 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 68/94] aspeed/hace: Fix out-of-bounds read in has_padding() Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 70/94] hw/i2c/microbit_i2c: Don't index off end of twi_read_sequence[] Michael Tokarev
                   ` (25 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Cédric Le Goater, Katherine Leaver,
	Michael Tokarev

From: Cédric Le Goater <clg@redhat.com>

In accumulate mode, total_req_len is incremented with plen (hwaddr)
for each hash request. Repeated additions can overflow total_req_len
(uint32_t) and potentially bypass validation checks in has_padding().

Add a helper function to detect overflow before incrementing
total_req_len and reject the request if overflow would occur.

Reported-by: Katherine Leaver <katherine.j.leaver@gmail.com>
Cc: qemu-stable@nongnu.org
Fixes: 5cd7d8564a8b ("aspeed/hace: Support AST2600 HACE")
Link: https://lore.kernel.org/qemu-devel/20260504213421.710035-3-clg@redhat.com
Signed-off-by: Cédric Le Goater <clg@redhat.com>
(cherry picked from commit c6aa2d0ac161f2a58a8fbab9a15e846278661158)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c
index ef698b3ecb..0504d61cbf 100644
--- a/hw/misc/aspeed_hace.c
+++ b/hw/misc/aspeed_hace.c
@@ -205,6 +205,19 @@ static uint64_t hash_get_source_addr(AspeedHACEState *s)
     return src_addr;
 }
 
+static bool hash_accumulate_len(AspeedHACEState *s, hwaddr plen)
+{
+    if (plen > UINT32_MAX - s->total_req_len) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: total_req_len overflow, current=0x%x, adding=0x%"
+                      HWADDR_PRIx "\n", __func__, s->total_req_len, plen);
+        return false;
+    }
+
+    s->total_req_len += plen;
+    return true;
+}
+
 static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov,
                                    bool acc_mode, bool *acc_final_request)
 {
@@ -232,7 +245,9 @@ static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov,
     iov_idx = 1;
 
     if (acc_mode) {
-        s->total_req_len += plen;
+        if (!hash_accumulate_len(s, plen)) {
+            return -1;
+        }
 
         if (has_padding(s, &iov[0], plen, &total_msg_len,
                         &pad_offset)) {
@@ -299,7 +314,9 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov,
 
         iov[iov_idx].iov_base = haddr;
         if (acc_mode) {
-            s->total_req_len += plen;
+            if (!hash_accumulate_len(s, plen)) {
+                return -1;
+            }
 
             if (has_padding(s, &iov[iov_idx], plen, &total_msg_len,
                             &pad_offset)) {
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 70/94] hw/i2c/microbit_i2c: Don't index off end of twi_read_sequence[]
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (10 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 69/94] aspeed/hace: Prevent total_req_len overflow Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 71/94] ati-vga: fix ati_set_dirty address calculation Michael Tokarev
                   ` (24 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Peter Maydell, Philippe Mathieu-Daudé,
	Michael Tokarev

From: Peter Maydell <peter.maydell@linaro.org>

If the guest tries to read more bytes from our fake stub I2C device
than we have provided, we incorrectly read one byte beyond the end of
this array. Avoid this, and instead keep reporting the RXD register
as containing the last byte of the "data transfer".

Cc: qemu-stable@nongnu.org
Fixes: 9d68bf564ec ("arm: Stub out NRF51 TWI magnetometer/accelerometer detection")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3408
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20260501162634.4092394-1-peter.maydell@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit a824f3531a44cbd19bcd9dd0ca48e5805c781e02)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/i2c/microbit_i2c.c b/hw/i2c/microbit_i2c.c
index 2291d6370e..d9689b6f1a 100644
--- a/hw/i2c/microbit_i2c.c
+++ b/hw/i2c/microbit_i2c.c
@@ -41,8 +41,13 @@ static uint64_t microbit_i2c_read(void *opaque, hwaddr addr, unsigned int size)
         data = 0x01;
         break;
     case NRF51_TWI_REG_RXD:
+        /*
+         * Return the next byte from our fake data sequence. If
+         * the guest keeps reading the register after that, keep
+         * returning the same last byte value.
+         */
         data = twi_read_sequence[s->read_idx];
-        if (s->read_idx < G_N_ELEMENTS(twi_read_sequence)) {
+        if (s->read_idx + 1 < G_N_ELEMENTS(twi_read_sequence)) {
             s->read_idx++;
         }
         break;
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 71/94] ati-vga: fix ati_set_dirty address calculation
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (11 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 70/94] hw/i2c/microbit_i2c: Don't index off end of twi_read_sequence[] Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 72/94] tests/qtest/iommu-smmuv3-test: Skip if no TCG GICv3 device present Michael Tokarev
                   ` (23 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Chad Jablonski, BALATON Zoltan,
	Philippe Mathieu-Daudé, Michael Tokarev

From: Chad Jablonski <chad@jablonski.xyz>

This fixes three bugs with the ati_set_dirty address calculation.

First, vbe_start_addr is a word offset. All other values in the
calculation are byte offsets. It must be converted to bytes.

Second, when setting the dirty region with memory_region_set_dirty
the vbe_start_addr is used to calculate the start of the dirty region.
This is a problem because the vbe_start_addr is the offset at which scan out
begins. This puts it in the visible screen coordinate system. The dirty
region however is in the virtual screen coordinate system. This can cause both
overmarking and missed updates. This is removed from the calculation.

Third, when the start address of a blit is outside of the bounds check
the entire blit is missed and not set to dirty. This happens even if the
blit does partially overlap with the visible screen. The fix here is to
find the intersection of the visible screen and the blit and mark only
that region as dirty.

This does not attempt to apply clipping to the blit. So there will be
overmarking in some cases.

Signed-off-by: Chad Jablonski <chad@jablonski.xyz>
[balaton: drop excess parenthesis, use offsets instead of pointers]
Reviewed-by: BALATON Zoltan <balaton@eik.bme.hu>
Tested-by: BALATON Zoltan <balaton@eik.bme.hu>
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
Message-ID: <20260506153920.C6B27596978@zero.eik.bme.hu>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 6197c11dd5d2d5deefc553a663a37139e38c5ac9)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c
index 504d1c5708..48498677c7 100644
--- a/hw/display/ati_2d.c
+++ b/hw/display/ati_2d.c
@@ -69,18 +69,28 @@ typedef struct {
 static void ati_set_dirty(VGACommonState *vga, const ATI2DCtx *ctx)
 {
     DisplaySurface *ds = qemu_console_surface(vga->con);
+    unsigned int bypp = ctx->bpp / 8;
+    hwaddr dirty_start = ctx->dst_offset + ctx->dst.x * bypp +
+                         ctx->dst.y * ctx->dst_stride;
+    hwaddr dirty_end = dirty_start + ctx->dst.width * bypp +
+                       (ctx->dst.height - 1) * ctx->dst_stride;
+    /*
+     * The blit may be outside of the visible screen (e.g. virtual desktops.)
+     * Dirty only the intersection of the visible screen and the blit.
+     */
+    hwaddr vis_start = vga->vbe_start_addr * 4;
+    hwaddr vis_end = vis_start + vga->vbe_regs[VBE_DISPI_INDEX_YRES] *
+                       vga->vbe_line_offset;
+    hwaddr start = MAX(vis_start, dirty_start);
+    hwaddr end = MIN(vis_end, dirty_end);
 
     (void)ds;
     DPRINTF("%p %u ds: %p %d %d rop: %x\n", vga->vram_ptr, vga->vbe_start_addr,
             surface_data(ds), surface_stride(ds), surface_bits_per_pixel(ds),
             ctx->rop3 >> 16);
-    if (ctx->dst_bits >= vga->vram_ptr + vga->vbe_start_addr &&
-        ctx->dst_bits < vga->vram_ptr + vga->vbe_start_addr +
-        vga->vbe_regs[VBE_DISPI_INDEX_YRES] * vga->vbe_line_offset) {
-        memory_region_set_dirty(&vga->vram,
-                                vga->vbe_start_addr + ctx->dst_offset +
-                                ctx->dst.y * ctx->dst_stride,
-                                ctx->dst.height * ctx->dst_stride);
+
+    if (start < end) {
+        memory_region_set_dirty(&vga->vram, start, end - start);
     }
 }
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 72/94] tests/qtest/iommu-smmuv3-test: Skip if no TCG GICv3 device present
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (12 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 71/94] ati-vga: fix ati_set_dirty address calculation Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 73/94] meson.build: Add -fzero-init-padding-bits=all Michael Tokarev
                   ` (22 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Peter Maydell, Fabiano Rosas, Eric Auger,
	Michael Tokarev

From: Peter Maydell <peter.maydell@linaro.org>

On a KVM-only (--disable-tcg) build, the iommu-smmuv3 qtest fails:

qemu-system-aarch64: QTest does not support GICv3 emulation
Broken pipe
../../tests/qtest/libqtest.c:201: kill_qemu() tried to terminate QEMU process but encountered exit status 1 (expected 0)

This is because the test runs the virt board with the qtest
accelerator and gic-version=3.  In the virt board this selects the
TCG (emulated) GICv3, but in a --disable-tcg build we don't compile
that device, only the KVM GICv3 (which isn't usable with qtest).

Add a check to the test so we skip it if the arm-gicv3 device isn't
in the QEMU binary.

Cc: qemu-stable@nongnu.org
Fixes: d8d19c31b220142641 ("tests/qtest: Add SMMUv3 bare-metal test using iommu-testdev")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
(cherry picked from commit 0129c626503c6d7220848a1f944a8f8e033ceaf9)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/tests/qtest/iommu-smmuv3-test.c b/tests/qtest/iommu-smmuv3-test.c
index dae9821b92..708fae5fd3 100644
--- a/tests/qtest/iommu-smmuv3-test.c
+++ b/tests/qtest/iommu-smmuv3-test.c
@@ -64,6 +64,11 @@ static void run_smmuv3_translation(const QSMMUTestConfig *cfg)
         g_test_skip("virt machine not available");
         return;
     }
+    if (!qtest_has_device("arm-gicv3")) {
+        /* This can happen for a KVM-only build: qtest uses the TCG GICv3 */
+        g_test_skip("gicv3 not available");
+        return;
+    }
 
     /* Initialize QEMU environment for SMMU testing */
     qts = qtest_init("-machine virt,acpi=off,gic-version=3,iommu=smmuv3 "
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 73/94] meson.build: Add -fzero-init-padding-bits=all
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (13 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 72/94] tests/qtest/iommu-smmuv3-test: Skip if no TCG GICv3 device present Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 74/94] hw/remote/machine.c: Mark x-remote machine as OK for AArch64 and AArch32 Michael Tokarev
                   ` (21 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Peter Maydell, Daniel P. Berrangé,
	Richard Henderson, Pierrick Bouvier, Michael Tokarev

From: Peter Maydell <peter.maydell@linaro.org>

The C standard doesn't always guarantee that struct and union padding
bits are zero initialized, even if the code initializes a struct.
For QEMU, this is potentially problematic, because we often have
structs that match data structures in guest memory, where we
initialize them and then bulk copy them into the guest.  If the
compiler didn't zero init the whole of the memory containing the
struct, we could potentially leak random data from the host into the
guest via the padding bytes.

We already use -ftrivial-auto-var-init=zero, which will zero out
padding in many of these cases, but -fzero-init-padding-bits=all
closes some gaps, for example cases where we initialize a
variable with a struct initializer, and cases involving unions.

Follow the Linux kernel in using both options. Compare kernel
commit dce4aab8441 ("kbuild: Use -fzero-init-padding-bits=all").

This option exists in gcc-15 and above; it's not supported
by clang, but clang documents that it guarantees zero init
of these cases always:
https://clang.llvm.org/docs/LanguageExtensions.html#union-and-aggregate-initialization-in-c
Older gcc which don't have the option behave as if it were set.

(These options are passed through the cc.get_supported_arguments()
filter, so we don't need to do anything extra to avoid passing it to
a compiler that doesn't recognize it.)

Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Message-id: 20260508104723.2144051-1-peter.maydell@linaro.org
(cherry picked from commit a163fc1f864bef27f6e527cbad9defba7af9e60a)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/meson.build b/meson.build
index d7b03e4746..51f5f2851a 100644
--- a/meson.build
+++ b/meson.build
@@ -684,6 +684,12 @@ hardening_flags = [
     # it harder to take advantage of uninitialized stack
     # data to drive exploits
     '-ftrivial-auto-var-init=zero',
+    # Ensure GCC zero-initializes padding bits and trailing fields in
+    # unions. This avoids potentially leaking host data into the guest
+    # when we init a struct and copy it into guest memory.  GCC prior
+    # to GCC 15 and clang don't have this, but they zero the padding
+    # and trailing portions of a union by default.
+    '-fzero-init-padding-bits=all',
 ]
 
 # Zero out registers used during a function call
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 74/94] hw/remote/machine.c: Mark x-remote machine as OK for AArch64 and AArch32
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (14 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 73/94] meson.build: Add -fzero-init-padding-bits=all Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 75/94] tests/functional/qemu_test/asset.py: Don't use setxattr when it doesn't exist Michael Tokarev
                   ` (20 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Peter Maydell, Pierrick Bouvier,
	Philippe Mathieu-Daudé, Michael Tokarev

From: Peter Maydell <peter.maydell@linaro.org>

When we updated Arm and AArch64 board types to mark them for the
target_machine_typename() filter, we forgot about the "x-remote"
machine type, which meant that it disappeared from the set of board
types exposed on the qemu-system-arm and qemu-system-aarch64
binaries.  We didn't notice this, because although we have a
functional test for it, it requires the KVM accelerator and we don't
run the functional tests on an AArch64 host in CI.

Mark the machine as being OK to expose in qemu-system-arm and
qemu-system-aarch64, in the same way we do for the "none" machine
type. This fixes a check-functional failure on aarch64 host, where
it would otherwise fail with:
   qemu-system-aarch64: unsupported machine type: "x-remote"

Cc: qemu-stable@nongnu.org
Fixes: eb796c55513d9d39 ("hw/core: Allow ARM/Aarch64 binaries to use the 'none' machine")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-id: 20260507194728.2034696-2-peter.maydell@linaro.org
(cherry picked from commit 4e8ac6857faab29f8d6e149f4d71aeb057884496)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/remote/machine.c b/hw/remote/machine.c
index ced782f6a9..df08f64019 100644
--- a/hw/remote/machine.c
+++ b/hw/remote/machine.c
@@ -24,6 +24,7 @@
 #include "hw/core/qdev.h"
 #include "hw/remote/vfio-user-obj.h"
 #include "hw/pci/msi.h"
+#include "hw/arm/machines-qom.h"
 
 static void remote_machine_init(MachineState *machine)
 {
@@ -148,6 +149,8 @@ static const TypeInfo remote_machine = {
     .class_init = remote_machine_class_init,
     .interfaces = (const InterfaceInfo[]) {
         { TYPE_HOTPLUG_HANDLER },
+        { TYPE_TARGET_AARCH64_MACHINE },
+        { TYPE_TARGET_ARM_MACHINE },
         { }
     }
 };
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 75/94] tests/functional/qemu_test/asset.py: Don't use setxattr when it doesn't exist
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (15 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 74/94] hw/remote/machine.c: Mark x-remote machine as OK for AArch64 and AArch32 Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 76/94] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning Michael Tokarev
                   ` (19 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Peter Maydell, Daniel P. Berrangé,
	Alex Bennée, Thomas Huth, Michael Tokarev

From: Peter Maydell <peter.maydell@linaro.org>

The Python os.setxattr() API is Linux-specific, so trying to use
it on other OSes triggers a failure:

  File "/Users/pm215/src/qemu/tests/functional/qemu_test/asset.py",
line 227, in fetch
    os.setxattr(str(tmp_cache_file), "user.qemu-asset-url",
    ^^^^^^^^^^^
AttributeError: module 'os' has no attribute 'setxattr'

Since we only set the attributes here for informational
purposes, skip them when os.setxattr() isn't available.

Cc: qemu-stable@nongnu.org
Fixes: 9903217a4ed013 ("tests/functional: add a module for handling asset download & caching")
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Thomas Huth <th.huth+qemu@posteo.eu>
Message-id: 20260501115506.3792110-1-peter.maydell@linaro.org
(cherry picked from commit 039b057c09c6a9742b91b8f29604651ba3fdb558)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py
index 51a434b2b7..0abd89e0a3 100644
--- a/tests/functional/qemu_test/asset.py
+++ b/tests/functional/qemu_test/asset.py
@@ -223,11 +223,14 @@ def fetch(self):
             raise AssetError(self, "Download retries exceeded", transient=True)
 
         try:
-            # Set these just for informational purposes
-            os.setxattr(str(tmp_cache_file), "user.qemu-asset-url",
-                        self.url.encode('utf8'))
-            os.setxattr(str(tmp_cache_file), "user.qemu-asset-hash",
-                        self.hash.encode('utf8'))
+            # Set these just for informational purposes. Note that
+            # setxattr is Linux-only; as this is only informational
+            # we can simply skip it on other platforms.
+            if hasattr(os, "setxattr"):
+                os.setxattr(str(tmp_cache_file), "user.qemu-asset-url",
+                            self.url.encode('utf8'))
+                os.setxattr(str(tmp_cache_file), "user.qemu-asset-hash",
+                            self.hash.encode('utf8'))
         except OSError as e:
             self.log.debug("Unable to set xattr on %s: %s", tmp_cache_file, e)
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 76/94] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (16 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 75/94] tests/functional/qemu_test/asset.py: Don't use setxattr when it doesn't exist Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 77/94] hw/nvme: fix admin cq msix setup Michael Tokarev
                   ` (18 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Scott J. Goldman, Mohamed Mediouni, Peter Maydell,
	Michael Tokarev

From: "Scott J. Goldman" <scottjgo@gmail.com>

Commit b5f8f77271 ("accel/hvf: Implement WFI without using pselect()")
changed hvf_wfi() from blocking the vCPU thread with pselect() to
returning EXCP_HLT, intending QEMU's main event loop to handle the
idle wait. However, cpu->halted was never set, so cpu_thread_is_idle()
always returns false and the vCPU thread spins at 100% CPU per core
while the guest is idle.

Fix this by:

1. Setting cpu->halted = 1 in hvf_wfi() so the vCPU thread sleeps on
   halt_cond in qemu_process_cpu_events().

2. Arming a per-vCPU QEMU_CLOCK_VIRTUAL timer to fire when the guest's
   virtual timer (CNTV_CVAL_EL0) would expire. This is necessary
   because HVF only delivers HV_EXIT_REASON_VTIMER_ACTIVATED during
   hv_vcpu_run(), which is not called while the CPU is halted. The
   timer callback mirrors the VTIMER_ACTIVATED handler: it raises the
   vtimer IRQ through the GIC and marks vtimer_masked, causing the
   interrupt delivery chain to wake the vCPU via qemu_cpu_kick().

3. Clearing cpu->halted in hvf_arch_vcpu_exec() when cpu_has_work()
   indicates a pending interrupt, and cancelling the WFI timer.

4. Re-arming the WFI timer from hvf_vm_state_change() on the resume
   transition for any halted vCPU, since the QEMUTimer is per-instance
   state and is not migrated. After cpu_synchronize_all_states() the
   migrated vtimer state is mirrored in env, so we can read CNTV_CTL
   and CNTV_CVAL from there. If the vtimer has already expired by the
   time the destination resumes, hvf_wfi_timer_cb() is invoked
   directly so the halted vCPU is woken up.

All wfi_timer handling (allocation, arming, deletion, and the resume
re-arm) is gated on !hvf_irqchip_in_kernel(): with the Apple in-kernel
vGIC, HVF owns the vtimer and delivers wake-ups itself.

Note for stable backports: this commit won't apply to 11.0 as
it has changes to handle the hvf in-kernel irqchip support that
landed after the 11.0 release. The v3 version of this commit:
  https://patchew.org/QEMU/20260427195516.46256-1-scottjgo@gmail.com/
should be suitable for 11.0 backporting (it is essentially
identical except that it doesn't make the changes conditional
on !hvf_irqchip_in_kernel()).

Cc: qemu-stable@nongnu.org
Fixes: b5f8f77271 ("accel/hvf: Implement WFI without using pselect()")
Signed-off-by: Scott J. Goldman <scottjgo@gmail.com>
Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
[PMM: added note about stable backports to commit message]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit a86024eb2df56f7664cef16ec8e9a50a1dc3dd2f)
(Mjt: add hvf_irqchip_in_kernel() define)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/include/system/hvf_int.h b/include/system/hvf_int.h
index 2621164cb2..58fb865eba 100644
--- a/include/system/hvf_int.h
+++ b/include/system/hvf_int.h
@@ -48,6 +48,7 @@ struct AccelCPUState {
     hv_vcpu_exit_t *exit;
     bool vtimer_masked;
     bool guest_debug_enabled;
+    struct QEMUTimer *wfi_timer;
 #endif
 };
 
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
index 5fc8f6bbbd..5016783062 100644
--- a/target/arm/hvf/hvf.c
+++ b/target/arm/hvf/hvf.c
@@ -28,6 +28,7 @@
 #include "hw/core/boards.h"
 #include "hw/core/irq.h"
 #include "qemu/main-loop.h"
+#include "qemu/timer.h"
 #include "system/cpus.h"
 #include "arm-powerctl.h"
 #include "target/arm/cpu.h"
@@ -40,6 +41,8 @@
 
 #include "gdbstub/enums.h"
 
+#define hvf_irqchip_in_kernel() 0 /* stub for qemu 11.0.x */
+
 #define MDSCR_EL1_SS_SHIFT  0
 #define MDSCR_EL1_MDE_SHIFT 15
 
@@ -301,6 +304,8 @@ void hvf_arm_init_debug(void)
 #define TMR_CTL_IMASK   (1 << 1)
 #define TMR_CTL_ISTATUS (1 << 2)
 
+static void hvf_wfi_timer_cb(void *opaque);
+
 static uint32_t chosen_ipa_bit_size;
 
 typedef struct HVFVTimer {
@@ -1214,6 +1219,11 @@ void hvf_arch_vcpu_destroy(CPUState *cpu)
 {
     hv_return_t ret;
 
+    if (!hvf_irqchip_in_kernel()) {
+        timer_free(cpu->accel->wfi_timer);
+        cpu->accel->wfi_timer = NULL;
+    }
+
     ret = hv_vcpu_destroy(cpu->accel->fd);
     assert_hvf_ok(ret);
 }
@@ -1352,6 +1362,11 @@ int hvf_arch_init_vcpu(CPUState *cpu)
                               arm_cpu->isar.idregs[ID_AA64MMFR0_EL1_IDX]);
     assert_hvf_ok(ret);
 
+    if (!hvf_irqchip_in_kernel()) {
+        cpu->accel->wfi_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                             hvf_wfi_timer_cb, cpu);
+    }
+
     aarch64_add_sme_properties(OBJECT(cpu));
     return 0;
 }
@@ -2027,6 +2042,62 @@ static uint64_t hvf_vtimer_val_raw(void)
     return mach_absolute_time() - hvf_state->vtimer_offset;
 }
 
+static void hvf_wfi_timer_cb(void *opaque)
+{
+    CPUState *cpu = opaque;
+    ARMCPU *arm_cpu = ARM_CPU(cpu);
+
+    /*
+     * vtimer expired while the CPU was halted for WFI.
+     * Mirror HV_EXIT_REASON_VTIMER_ACTIVATED: raise the vtimer
+     * interrupt and mark as masked so hvf_sync_vtimer() will
+     * check and unmask when the guest handles it.
+     *
+     * The interrupt delivery chain (GIC -> cpu_interrupt ->
+     * qemu_cpu_kick) wakes the vCPU thread from halt_cond.
+     */
+    qemu_set_irq(arm_cpu->gt_timer_outputs[GTIMER_VIRT], 1);
+    cpu->accel->vtimer_masked = true;
+}
+
+/*
+ * Arm a host-side QEMU_CLOCK_VIRTUAL timer to fire when the guest's
+ * vtimer (CNTV_CVAL_EL0) is scheduled to expire. HVF only delivers
+ * HV_EXIT_REASON_VTIMER_ACTIVATED during hv_vcpu_run(), which we won't
+ * call while the vCPU is halted, so we need this to wake the vCPU.
+ *
+ * QEMU_CLOCK_VIRTUAL pauses while the VM is stopped, which keeps the
+ * timer in lockstep with the guest's view of vtime across pause/resume.
+ *
+ * Caller must supply the current CNTV_CTL_EL0 and CNTV_CVAL_EL0 values,
+ * since the appropriate source (HVF vs. env) depends on context.
+ *
+ * Returns 0 if the timer was armed (or if the vtimer is disabled/masked
+ * and the vCPU should still halt waiting on another event), or -1 if
+ * the vtimer has already expired.
+ */
+static int hvf_arm_wfi_timer(CPUState *cpu, uint64_t ctl, uint64_t cval)
+{
+    ARMCPU *arm_cpu = ARM_CPU(cpu);
+    uint64_t now;
+    int64_t delta_ns;
+
+    if (!(ctl & TMR_CTL_ENABLE) || (ctl & TMR_CTL_IMASK)) {
+        return 0;
+    }
+
+    now = hvf_vtimer_val_raw();
+    if (cval <= now) {
+        return -1;
+    }
+
+    delta_ns = muldiv64(cval - now, NANOSECONDS_PER_SECOND,
+                        arm_cpu->gt_cntfrq_hz);
+    timer_mod(cpu->accel->wfi_timer,
+              qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + delta_ns);
+    return 0;
+}
+
 static int hvf_wfi(CPUState *cpu)
 {
     if (cpu_has_work(cpu)) {
@@ -2037,6 +2108,29 @@ static int hvf_wfi(CPUState *cpu)
         return 0;
     }
 
+    if (!hvf_irqchip_in_kernel()) {
+        uint64_t ctl, cval;
+        hv_return_t r;
+
+        /*
+         * Read the vtimer state directly from HVF. We're on the vCPU
+         * thread, just exited from hv_vcpu_run(), so HVF holds the
+         * authoritative values and env may be stale.
+         */
+        r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CTL_EL0,
+                                &ctl);
+        assert_hvf_ok(r);
+        r = hv_vcpu_get_sys_reg(cpu->accel->fd, HV_SYS_REG_CNTV_CVAL_EL0,
+                                &cval);
+        assert_hvf_ok(r);
+
+        if (hvf_arm_wfi_timer(cpu, ctl, cval) < 0) {
+            /* vtimer already expired, don't halt */
+            return 0;
+        }
+    }
+
+    cpu->halted = 1;
     return EXCP_HLT;
 }
 
@@ -2332,7 +2426,13 @@ int hvf_arch_vcpu_exec(CPUState *cpu)
     hv_return_t r;
 
     if (cpu->halted) {
-        return EXCP_HLT;
+        if (!cpu_has_work(cpu)) {
+            return EXCP_HLT;
+        }
+        cpu->halted = 0;
+        if (!hvf_irqchip_in_kernel()) {
+            timer_del(cpu->accel->wfi_timer);
+        }
     }
 
     flush_cpu_state(cpu);
@@ -2381,6 +2481,46 @@ static void hvf_vm_state_change(void *opaque, bool running, RunState state)
         /* Update vtimer offset on all CPUs */
         hvf_state->vtimer_offset = mach_absolute_time() - s->vtimer_val;
         cpu_synchronize_all_states();
+
+        /*
+         * After migration restore (or any resume), the wfi_timer is not
+         * scheduled on this QEMU instance, so re-arm it for any halted
+         * vCPU with a pending vtimer. For a non-migration resume the
+         * QEMU_CLOCK_VIRTUAL timer was already scheduled; recomputing the
+         * deadline produces the same value and is a harmless no-op.
+         *
+         * cpu_synchronize_all_states() above ensures env mirrors the
+         * authoritative vtimer state (whether that came from HVF or from
+         * the migration stream), so we can safely read it here from the
+         * iothread.
+         *
+         * Only applies when we own the wfi_timer; with an in-kernel vGIC
+         * the timer is never allocated and HVF handles vtimer wake-ups.
+         */
+        if (!hvf_irqchip_in_kernel()) {
+            CPUState *cpu;
+
+            CPU_FOREACH(cpu) {
+                ARMCPU *arm_cpu;
+                uint64_t ctl, cval;
+
+                if (!cpu->accel || !cpu->halted) {
+                    continue;
+                }
+
+                arm_cpu = ARM_CPU(cpu);
+                ctl = arm_cpu->env.cp15.c14_timer[GTIMER_VIRT].ctl;
+                cval = arm_cpu->env.cp15.c14_timer[GTIMER_VIRT].cval;
+
+                if (hvf_arm_wfi_timer(cpu, ctl, cval) < 0) {
+                    /*
+                     * vtimer already expired while we were paused; raise
+                     * the IRQ now so the halted vCPU wakes up.
+                     */
+                    hvf_wfi_timer_cb(cpu);
+                }
+            }
+        }
     } else {
         /* Remember vtimer value on every pause */
         s->vtimer_val = hvf_vtimer_val_raw();
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 77/94] hw/nvme: fix admin cq msix setup
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (17 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 76/94] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 78/94] linux-user: Fix AT_EXECFN in AUXV for symlinked programs Michael Tokarev
                   ` (17 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Klaus Jensen, Andreas Hindborg, Michael Tokarev

From: Klaus Jensen <k.jensen@samsung.com>

If MSI-X is not enabled when the admin completion queue is created,
msix_vector_use() is not called. But, if MSI-X is subsequently enabled,
msix_notify() will fail to fire the interrupt because the use count for
the vector remains at 0.

msix_vector_use/unuse should be called if MSI-X is *present*, not
*enabled*. Fix this.

Cc: qemu-stable@nongnu.org
Reported-by: Andreas Hindborg <a.hindborg@samsung.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
(cherry picked from commit 2293d8b4bd88d3f29730cfd608935f77247919b6)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index be6c7028cb..8463fd3e9a 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -5517,7 +5517,7 @@ static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n)
         event_notifier_set_handler(&cq->notifier, NULL);
         event_notifier_cleanup(&cq->notifier);
     }
-    if (msix_enabled(pci) && cq->irq_enabled) {
+    if (msix_present(pci) && cq->irq_enabled) {
         msix_vector_unuse(pci, cq->vector);
     }
     if (cq->cqid) {
@@ -5558,7 +5558,7 @@ static void nvme_init_cq(NvmeCQueue *cq, NvmeCtrl *n, uint64_t dma_addr,
 {
     PCIDevice *pci = PCI_DEVICE(n);
 
-    if (msix_enabled(pci) && irq_enabled) {
+    if (msix_present(pci) && irq_enabled) {
         msix_vector_use(pci, vector);
     }
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 78/94] linux-user: Fix AT_EXECFN in AUXV for symlinked programs
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (18 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 77/94] hw/nvme: fix admin cq msix setup Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 79/94] linux-user/sh4: Fix target_ucontext tuc_link field type Michael Tokarev
                   ` (16 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Helge Deller, Michael Tokarev

From: Helge Deller <deller@gmx.de>

The AT_EXECFN entry in AUXV needs to keep the value which was used when
the program was started. Especially for symlinked programs qemu should
not try to resolve the realpath.

Here is a reproducer:
(arm64-chroot)root@p100:/# cd /usr/bin
(arm64-chroot)root@p100:/usr/bin# ln -s echo testprog
(arm64-chroot)root@p100:/usr/bin# LD_SHOW_AUXV=1 ./testprog | grep AT_EXECFN
AT_EXECFN:            ./testprog

In this example, "./testprog" is the correct output, and not "/usr/bin/echo".

This patch fixes parts of commit 258bec39 ("linux-user: Fix access to
/proc/self/exe").

Fixes: 258bec39 ("linux-user: Fix access to /proc/self/exe")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3379
Signed-off-by: Helge Deller <deller@gmx.de>
(cherry picked from commit 6b5aef7cac9dab7c16451588cff6615eb2048293)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/linux-user/main.c b/linux-user/main.c
index 86d04cca3c..c08c73fd80 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -772,8 +772,10 @@ int main(int argc, char **argv, char **envp)
     }
 
     /* Resolve executable file name to full path name */
-    if (realpath(exec_path, real_exec_path)) {
-        exec_path = real_exec_path;
+    /* Keep how we started the program in exec_path, e.g. "./my_program" */
+    /* Store real path in real_exec_path, e.g. "/usr/local/bin/my_program" */
+    if (!realpath(exec_path, real_exec_path)) {
+        printf("Could not resolve %s\n", exec_path);
     }
 
     /*
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d3d9fffb54..65bbeb8551 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8790,9 +8790,9 @@ static int maybe_do_fake_open(CPUArchState *cpu_env, int dirfd,
             return -1;
         }
         if (safe) {
-            return safe_openat(dirfd, exec_path, flags, mode);
+            return safe_openat(dirfd, real_exec_path, flags, mode);
         } else {
-            return openat(dirfd, exec_path, flags, mode);
+            return openat(dirfd, real_exec_path, flags, mode);
         }
     }
 
@@ -8929,9 +8929,9 @@ ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz)
          * Don't worry about sign mismatch as earlier mapping
          * logic would have thrown a bad address error.
          */
-        ret = MIN(strlen(exec_path), bufsiz);
+        ret = MIN(strlen(real_exec_path), bufsiz);
         /* We cannot NUL terminate the string. */
-        memcpy(buf, exec_path, ret);
+        memcpy(buf, real_exec_path, ret);
     } else {
         ret = readlink(path(pathname), buf, bufsiz);
     }
@@ -9022,7 +9022,7 @@ static int do_execv(CPUArchState *cpu_env, int dirfd,
 
     const char *exe = p;
     if (is_proc_myself(p, "exe")) {
-        exe = exec_path;
+        exe = real_exec_path;
     }
     ret = is_execveat
         ? safe_execveat(dirfd, exe, argp, envp, flags)
@@ -11033,9 +11033,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
                  * Don't worry about sign mismatch as earlier mapping
                  * logic would have thrown a bad address error.
                  */
-                ret = MIN(strlen(exec_path), arg4);
+                ret = MIN(strlen(real_exec_path), arg4);
                 /* We cannot NUL terminate the string. */
-                memcpy(p2, exec_path, ret);
+                memcpy(p2, real_exec_path, ret);
             } else {
                 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
             }
diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h
index 24d35998f0..7730444aa5 100644
--- a/linux-user/user-internals.h
+++ b/linux-user/user-internals.h
@@ -24,6 +24,7 @@
 #include "exec/translation-block.h"
 
 extern char *exec_path;
+extern char real_exec_path[PATH_MAX];
 void init_task_state(TaskState *ts);
 void task_settid(TaskState *);
 void stop_all_tasks(void);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 79/94] linux-user/sh4: Fix target_ucontext tuc_link field type
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (19 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 78/94] linux-user: Fix AT_EXECFN in AUXV for symlinked programs Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 80/94] linux-user/sh4: Fix setup_sigtramp to match Linux kernel trampoline pattern Michael Tokarev
                   ` (15 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Matt Turner, Richard Henderson, Helge Deller,
	Michael Tokarev

From: Matt Turner <mattst88@gmail.com>

tuc_link is declared as 'struct target_ucontext *', which is a HOST
pointer.  On a 64-bit host running a 32-bit SH4 target, this is 8 bytes
instead of the 4 bytes the target expects, padding pushes tuc_mcontext
8 bytes past its correct offset.

When a signal handler receives ucontext_t *, every field accessed through
uc_mcontext (gregs[], pc, pr, ...) is read from the wrong address.  In
particular the saved PC comes back as a garbage stack value, which breaks
any code that initialises a libunwind cursor from the signal context.

Fix it by using abi_ulong, which is always sized to the target ABI (4
bytes for SH4), matching the layout the kernel and glibc agree on.  This
is the same pattern used by arm/signal.c.

Also remove the (unsigned long *) cast from the __put_user that zeros
tuc_link.  The cast was harmless when tuc_link was pointer-sized (8
bytes matching unsigned long on a 64-bit host), but after the type
change __put_user's sizeof dispatch would select stq_le_p (8-byte write)
for a now-4-byte field, silently overwriting the start of tuc_stack.

Neither this fix nor the companion setup_sigtramp fix is independently
sufficient: this fix corrects register values read from the signal context
but libunwind still cannot detect the frame without the correct trampoline
pattern; that fix makes the frame detectable but register reads remain
garbage without the correct ucontext layout.  Together they fix the
following libunwind tests on a 64-bit host:
  Gtest-sig-context, Gtest-trace, Ltest-init-local-signal,
  Ltest-sig-context, Ltest-trace

Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: qemu-stable@nongnu.org
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Helge Deller <deller@gmx.de>
(cherry picked from commit c3176e645774fcb795bf99c1c6c40c67432232db)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c
index 9ecc026fae..20d2bc8b2c 100644
--- a/linux-user/sh4/signal.c
+++ b/linux-user/sh4/signal.c
@@ -57,7 +57,7 @@ struct target_sigframe
 
 struct target_ucontext {
     target_ulong tuc_flags;
-    struct target_ucontext *tuc_link;
+    abi_ulong tuc_link;
     target_stack_t tuc_stack;
     struct target_sigcontext tuc_mcontext;
     target_sigset_t tuc_sigmask;        /* mask last for extensibility */
@@ -237,7 +237,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
 
     /* Create the ucontext.  */
     __put_user(0, &frame->uc.tuc_flags);
-    __put_user(0, (unsigned long *)&frame->uc.tuc_link);
+    __put_user(0, &frame->uc.tuc_link);
     target_save_altstack(&frame->uc.tuc_stack, regs);
     setup_sigcontext(&frame->uc.tuc_mcontext,
                      regs, set->sig[0]);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 80/94] linux-user/sh4: Fix setup_sigtramp to match Linux kernel trampoline pattern
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (20 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 79/94] linux-user/sh4: Fix target_ucontext tuc_link field type Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 81/94] blkdebug: Add 'delay-ns' option Michael Tokarev
                   ` (14 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Matt Turner, Richard Henderson, Helge Deller,
	Michael Tokarev

From: Matt Turner <mattst88@gmail.com>

QEMU used MOVW(2) (0x9300), which loads the syscall number from PC+4,
instead of the kernel's MOVW(7) (0x9305), which loads from PC+14.  The
kernel uses five "or r0,r0" nop pads between TRAP_NOARG and the syscall
number word to reach that offset.  libunwind's unw_is_signal_frame checks
for the exact kernel byte pattern 0xc3109305 at the frame PC, so QEMU's
compact layout was not detected, breaking unwinding through signal frames.

Expand each trampoline from 6 to 16 bytes matching the kernel layout
defined in arch/sh/kernel/signal_32.c:

  #define MOVW(n)    (0x9300|((n)-2))  /* Move mem word at PC+n to R3 */
  #define TRAP_NOARG 0xc310            /* Syscall w/no args (NR in R3) */
  #define OR_R0_R0   0x200b            /* or r0,r0 (insert to avoid hardware bug) */

  __put_user(MOVW(7),          &frame->retcode[0]);  /* 0x9305 */
  __put_user(TRAP_NOARG,       &frame->retcode[1]);  /* 0xc310 */
  __put_user(OR_R0_R0,         &frame->retcode[2]);  /* 0x200b */
  __put_user(OR_R0_R0,         &frame->retcode[3]);  /* 0x200b */
  __put_user(OR_R0_R0,         &frame->retcode[4]);  /* 0x200b */
  __put_user(OR_R0_R0,         &frame->retcode[5]);  /* 0x200b */
  __put_user(OR_R0_R0,         &frame->retcode[6]);  /* 0x200b */
  __put_user((__NR_sigreturn), &frame->retcode[7]);

The first two halfwords (MOVW(7) || TRAP_NOARG = 0xc3109305) form the
32-bit value libunwind checks at the frame PC, followed by two
OR_R0_R0 halfwords (0x200b200b) at PC+4.  The same layout applies to
the rt_sigreturn trampoline (lines 366-373 of signal_32.c).

Neither this fix nor the companion tuc_link fix is independently
sufficient: this fix makes signal frames detectable but register reads
remain garbage without the correct ucontext layout; that fix corrects the
ucontext layout but libunwind still cannot detect the frame without the
correct trampoline pattern.  Together they fix the following libunwind
tests on a 64-bit host:
  Gtest-sig-context, Gtest-trace, Ltest-init-local-signal,
  Ltest-sig-context, Ltest-trace

Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: qemu-stable@nongnu.org
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Helge Deller <deller@gmx.de>
(cherry picked from commit 9ac5aa72272117608482cad2430a75477263fe09)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c
index 20d2bc8b2c..d70be24c38 100644
--- a/linux-user/sh4/signal.c
+++ b/linux-user/sh4/signal.c
@@ -329,20 +329,42 @@ badframe:
     return -QEMU_ESIGRETURN;
 }
 
+/*
+ * "or r0,r0" nop used by the Linux kernel inline sigreturn trampolines to
+ * avoid a hardware bug (OR_R0_R0 in arch/sh/kernel/signal_32.c).  Five of
+ * these nops follow TRAP_NOARG, placing the syscall number word 14 bytes
+ * past the MOVW(7) instruction (at MOVW(7)'s load offset).  This yields the
+ * fixed 16-byte layout that libunwind's unw_is_signal_frame detects:
+ *   [MOVW(7), TRAP_NOARG, 5x NOP_OR, .word syscall_nr]
+ */
+#define NOP_OR 0x200b
+
 void setup_sigtramp(abi_ulong sigtramp_page)
 {
-    uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 6, 0);
+    uint16_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 16, 0);
     assert(tramp != NULL);
 
+    /* sigreturn trampoline (non-RT) at offset 0 */
     default_sigreturn = sigtramp_page;
-    __put_user(MOVW(2), &tramp[0]);
+    __put_user(MOVW(7), &tramp[0]);
     __put_user(TRAP_NOARG, &tramp[1]);
-    __put_user(TARGET_NR_sigreturn, &tramp[2]);
-
-    default_rt_sigreturn = sigtramp_page + 6;
-    __put_user(MOVW(2), &tramp[3]);
-    __put_user(TRAP_NOARG, &tramp[4]);
-    __put_user(TARGET_NR_rt_sigreturn, &tramp[5]);
-
-    unlock_user(tramp, sigtramp_page, 2 * 6);
+    __put_user(NOP_OR, &tramp[2]);
+    __put_user(NOP_OR, &tramp[3]);
+    __put_user(NOP_OR, &tramp[4]);
+    __put_user(NOP_OR, &tramp[5]);
+    __put_user(NOP_OR, &tramp[6]);
+    __put_user(TARGET_NR_sigreturn, &tramp[7]);
+
+    /* rt_sigreturn trampoline at offset 16 */
+    default_rt_sigreturn = sigtramp_page + 16;
+    __put_user(MOVW(7), &tramp[8]);
+    __put_user(TRAP_NOARG, &tramp[9]);
+    __put_user(NOP_OR, &tramp[10]);
+    __put_user(NOP_OR, &tramp[11]);
+    __put_user(NOP_OR, &tramp[12]);
+    __put_user(NOP_OR, &tramp[13]);
+    __put_user(NOP_OR, &tramp[14]);
+    __put_user(TARGET_NR_rt_sigreturn, &tramp[15]);
+
+    unlock_user(tramp, sigtramp_page, 2 * 16);
 }
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 81/94] blkdebug: Add 'delay-ns' option
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (21 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 80/94] linux-user/sh4: Fix setup_sigtramp to match Linux kernel trampoline pattern Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 82/94] block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE Michael Tokarev
                   ` (13 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

Sometimes reproducing a problem for debugging involves slow I/O, so
let's add something to blkdebug to make I/O slow when we need it. This
can be used either together with an error so that the request fails
after the delay, or with errno=0, which allows the request to succeed
after the delay.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-2-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit d5e4090177ad382e01084a1594a1a60a69f4c1cd)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/block/blkdebug.c b/block/blkdebug.c
index 8a4a8cb85e..b07c67611a 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -95,6 +95,7 @@ typedef struct BlkdebugRule {
             int immediately;
             int once;
             int64_t offset;
+            int64_t delay_ns;
         } inject;
         struct {
             int new_state;
@@ -144,6 +145,10 @@ static QemuOptsList inject_error_opts = {
             .name = "immediately",
             .type = QEMU_OPT_BOOL,
         },
+        {
+            .name = "delay-ns",
+            .type = QEMU_OPT_NUMBER,
+        },
         { /* end of list */ }
     },
 };
@@ -216,6 +221,8 @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
         rule->options.inject.once  = qemu_opt_get_bool(opts, "once", 0);
         rule->options.inject.immediately =
             qemu_opt_get_bool(opts, "immediately", 0);
+        rule->options.inject.delay_ns =
+            qemu_opt_get_number(opts, "delay-ns", 0);
         sector = qemu_opt_get_number(opts, "sector", -1);
         rule->options.inject.offset =
             sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
@@ -594,6 +601,7 @@ static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
     BlkdebugRule *rule = NULL;
     int error;
     bool immediately;
+    int64_t delay_ns;
 
     qemu_mutex_lock(&s->lock);
     QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
@@ -608,13 +616,14 @@ static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
         }
     }
 
-    if (!rule || !rule->options.inject.error) {
+    if (!rule) {
         qemu_mutex_unlock(&s->lock);
         return 0;
     }
 
     immediately = rule->options.inject.immediately;
     error = rule->options.inject.error;
+    delay_ns  = rule->options.inject.delay_ns;
 
     if (rule->options.inject.once) {
         QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
@@ -622,6 +631,10 @@ static int coroutine_fn rule_check(BlockDriverState *bs, uint64_t offset,
     }
 
     qemu_mutex_unlock(&s->lock);
+
+    if (delay_ns) {
+        qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, delay_ns);
+    }
     if (!immediately) {
         aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
         qemu_coroutine_yield();
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 508b081ac1..0efd51787b 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3919,6 +3919,9 @@
 #
 # @errno: error identifier (errno) to be returned; defaults to EIO
 #
+# @delay-ns: request delay before completion in nanoseconds
+#            (default: 0, since: 11.1)
+#
 # @sector: specifies the sector index which has to be affected in
 #     order to actually trigger the event; defaults to "any sector"
 #
@@ -3934,6 +3937,7 @@
             '*state': 'int',
             '*iotype': 'BlkdebugIOType',
             '*errno': 'int',
+            '*delay-ns': 'int',
             '*sector': 'int',
             '*once': 'bool',
             '*immediately': 'bool' } }
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 82/94] block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (22 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 81/94] blkdebug: Add 'delay-ns' option Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 83/94] block: Add flags parameter to blk_*_pdiscard() Michael Tokarev
                   ` (12 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

If a device uses blk_inc/dec_in_flight() in order to build macro
operations that involve multiple requests for the block layer and that
need to be completed as a unit before the BlockBackend can be considered
drained, it sets the stage for a deadlock: When a drain is requested,
the inner request at the BlockBackend level will be queued in
blk_wait_while_drained() and wait until the drained section ends, but at
the same time, drain_begin can only return if the whole macro operation
at the device level has completed.

Introduce a new interface to allow implementing the logic correctly:
Instead of queueing individual requests, blk_co_start_request() calls
blk_wait_while_drained() once at the beginning. The individual requests
must then set BDRV_REQ_NO_QUEUE to avoid being queued and running into
the deadlock; being wrapped in blk_co_start/end_request() makes sure
that drain_begin waits for them and they don't sneak in when the
BlockBackend is supposed to already be quiescent.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-3-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 34a67637767d3ed1ac813c44effe827bbfba5996)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/block/block-backend.c b/block/block-backend.c
index 9944657120..ee00440e28 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -82,6 +82,7 @@ struct BlockBackend {
     QemuMutex queued_requests_lock; /* protects queued_requests */
     CoQueue queued_requests;
     bool disable_request_queuing; /* atomic */
+    int start_request_count; /* atomic */
 
     VMChangeStateEntry *vmsh;
     bool force_allow_inactivate;
@@ -1306,10 +1307,16 @@ bool blk_in_drain(BlockBackend *blk)
 }
 
 /* To be called between exactly one pair of blk_inc/dec_in_flight() */
-static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
+static void coroutine_fn blk_wait_while_drained(BlockBackend *blk,
+                                                BdrvRequestFlags flags)
 {
     assert(blk->in_flight > 0);
 
+    if (flags & BDRV_REQ_NO_QUEUE) {
+        assert(qatomic_read(&blk->start_request_count));
+        return;
+    }
+
     if (qatomic_read(&blk->quiesce_counter) &&
         !qatomic_read(&blk->disable_request_queuing)) {
         /*
@@ -1335,7 +1342,7 @@ blk_co_do_preadv_part(BlockBackend *blk, int64_t offset, int64_t bytes,
     BlockDriverState *bs;
     IO_CODE();
 
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, flags);
     GRAPH_RDLOCK_GUARD();
 
     /* Call blk_bs() only after waiting, the graph may have changed */
@@ -1410,7 +1417,7 @@ blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
     BlockDriverState *bs;
     IO_CODE();
 
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, flags);
     GRAPH_RDLOCK_GUARD();
 
     /* Call blk_bs() only after waiting, the graph may have changed */
@@ -1523,6 +1530,19 @@ void blk_dec_in_flight(BlockBackend *blk)
     aio_wait_kick();
 }
 
+void coroutine_fn blk_co_start_request(BlockBackend *blk)
+{
+    blk_inc_in_flight(blk);
+    blk_wait_while_drained(blk, 0);
+    qatomic_inc(&blk->start_request_count);
+}
+
+void blk_end_request(BlockBackend *blk)
+{
+    qatomic_dec(&blk->start_request_count);
+    blk_dec_in_flight(blk);
+}
+
 static void error_callback_bh(void *opaque)
 {
     struct BlockBackendAIOCB *acb = opaque;
@@ -1741,7 +1761,7 @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
 {
     IO_CODE();
 
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
 
     if (!blk_co_is_available(blk)) {
@@ -1788,7 +1808,7 @@ blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
     int ret;
     IO_CODE();
 
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
 
     ret = blk_check_byte_request(blk, offset, bytes);
@@ -1834,7 +1854,7 @@ int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
 static int coroutine_fn blk_co_do_flush(BlockBackend *blk)
 {
     IO_CODE();
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
 
     if (!blk_co_is_available(blk)) {
@@ -2009,7 +2029,7 @@ int coroutine_fn blk_co_zone_report(BlockBackend *blk, int64_t offset,
     IO_CODE();
 
     blk_inc_in_flight(blk); /* increase before waiting */
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
     if (!blk_is_available(blk)) {
         blk_dec_in_flight(blk);
@@ -2034,7 +2054,7 @@ int coroutine_fn blk_co_zone_mgmt(BlockBackend *blk, BlockZoneOp op,
     IO_CODE();
 
     blk_inc_in_flight(blk);
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, 0);
     GRAPH_RDLOCK_GUARD();
 
     ret = blk_check_byte_request(blk, offset, len);
@@ -2058,7 +2078,7 @@ int coroutine_fn blk_co_zone_append(BlockBackend *blk, int64_t *offset,
     IO_CODE();
 
     blk_inc_in_flight(blk);
-    blk_wait_while_drained(blk);
+    blk_wait_while_drained(blk, flags);
     GRAPH_RDLOCK_GUARD();
     if (!blk_is_available(blk)) {
         blk_dec_in_flight(blk);
diff --git a/include/block/block-common.h b/include/block/block-common.h
index c8c626daea..895ea17541 100644
--- a/include/block/block-common.h
+++ b/include/block/block-common.h
@@ -215,8 +215,17 @@ typedef enum {
      */
     BDRV_REQ_NO_WAIT = 0x400,
 
+    /*
+     * Used between blk_co_start_request() and blk_end_request() to avoid
+     * that the request waits in a drained BlockBackend until the drained
+     * section ends. Waiting would cause a deadlock because drain waits for
+     * blk_end_request() to be called, but the request never completes
+     * because it waits for the drain to end.
+     */
+    BDRV_REQ_NO_QUEUE = 0x800,
+
     /* Mask of valid flags */
-    BDRV_REQ_MASK               = 0x7ff,
+    BDRV_REQ_MASK               = 0xfff,
 } BdrvRequestFlags;
 
 #define BDRV_O_NO_SHARE    0x0001 /* don't share permissions */
diff --git a/include/system/block-backend-io.h b/include/system/block-backend-io.h
index 6d5ac476fc..0248c1c36e 100644
--- a/include/system/block-backend-io.h
+++ b/include/system/block-backend-io.h
@@ -71,6 +71,8 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
 
 void blk_inc_in_flight(BlockBackend *blk);
 void blk_dec_in_flight(BlockBackend *blk);
+void coroutine_fn blk_co_start_request(BlockBackend *blk);
+void blk_end_request(BlockBackend *blk);
 
 bool coroutine_fn GRAPH_RDLOCK blk_co_is_inserted(BlockBackend *blk);
 bool co_wrapper_mixed_bdrv_rdlock blk_is_inserted(BlockBackend *blk);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 83/94] block: Add flags parameter to blk_*_pdiscard()
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (23 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 82/94] block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 84/94] ide: Minimal fix for deadlock between TRIM and drain Michael Tokarev
                   ` (11 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

All existing callers pass 0, but we need a way to pass BDRV_REQ_NO_QUEUE
for discard requests.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-4-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 53074ba0330ae8831abbae2521c012e1d9072ed3)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/block/block-backend.c b/block/block-backend.c
index ee00440e28..37ba7e9fc4 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1803,12 +1803,13 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
 
 /* To be called between exactly one pair of blk_inc/dec_in_flight() */
 static int coroutine_fn
-blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
+blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes,
+                   BdrvRequestFlags flags)
 {
     int ret;
     IO_CODE();
 
-    blk_wait_while_drained(blk, 0);
+    blk_wait_while_drained(blk, flags);
     GRAPH_RDLOCK_GUARD();
 
     ret = blk_check_byte_request(blk, offset, bytes);
@@ -1824,7 +1825,7 @@ static void coroutine_fn blk_aio_pdiscard_entry(void *opaque)
     BlkAioEmAIOCB *acb = opaque;
     BlkRwCo *rwco = &acb->rwco;
 
-    rwco->ret = blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes);
+    rwco->ret = blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes, 0);
     blk_aio_complete(acb);
 }
 
@@ -1838,13 +1839,13 @@ BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
 }
 
 int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
-                                 int64_t bytes)
+                                 int64_t bytes, BdrvRequestFlags flags)
 {
     int ret;
     IO_OR_GS_CODE();
 
     blk_inc_in_flight(blk);
-    ret = blk_co_do_pdiscard(blk, offset, bytes);
+    ret = blk_co_do_pdiscard(blk, offset, bytes, flags);
     blk_dec_in_flight(blk);
 
     return ret;
diff --git a/block/export/virtio-blk-handler.c b/block/export/virtio-blk-handler.c
index 3dd6c43af1..eaa6fc1906 100644
--- a/block/export/virtio-blk-handler.c
+++ b/block/export/virtio-blk-handler.c
@@ -122,7 +122,7 @@ virtio_blk_discard_write_zeroes(VirtioBlkHandler *handler, struct iovec *iov,
         }
 
         if (blk_co_pdiscard(blk, sector << VIRTIO_BLK_SECTOR_BITS,
-                            bytes) == 0) {
+                            bytes, 0) == 0) {
             return VIRTIO_BLK_S_OK;
         }
     }
diff --git a/block/mirror.c b/block/mirror.c
index 2fcded9e93..089856f4a8 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -454,7 +454,7 @@ static void coroutine_fn mirror_co_discard(void *opaque)
     *op->bytes_handled = op->bytes;
     op->is_in_flight = true;
 
-    ret = blk_co_pdiscard(op->s->target, op->offset, op->bytes);
+    ret = blk_co_pdiscard(op->s->target, op->offset, op->bytes, 0);
     mirror_write_complete(op, ret);
 }
 
@@ -1532,7 +1532,7 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method,
                          zero_bitmap_end - zero_bitmap_offset);
         }
         assert(!qiov);
-        ret = blk_co_pdiscard(job->target, offset, bytes);
+        ret = blk_co_pdiscard(job->target, offset, bytes, 0);
         break;
 
     default:
diff --git a/include/system/block-backend-io.h b/include/system/block-backend-io.h
index 0248c1c36e..fd84723d9d 100644
--- a/include/system/block-backend-io.h
+++ b/include/system/block-backend-io.h
@@ -218,9 +218,9 @@ int co_wrapper_mixed blk_zone_append(BlockBackend *blk, int64_t *offset,
                                          BdrvRequestFlags flags);
 
 int co_wrapper_mixed blk_pdiscard(BlockBackend *blk, int64_t offset,
-                                  int64_t bytes);
+                                  int64_t bytes, BdrvRequestFlags flags);
 int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset,
-                                 int64_t bytes);
+                                 int64_t bytes, BdrvRequestFlags flags);
 
 int co_wrapper_mixed blk_flush(BlockBackend *blk);
 int coroutine_fn blk_co_flush(BlockBackend *blk);
diff --git a/nbd/server.c b/nbd/server.c
index 620097c58c..78ec984409 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -2990,7 +2990,7 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
                                       "flush failed", errp);
 
     case NBD_CMD_TRIM:
-        ret = blk_co_pdiscard(exp->common.blk, request->from, request->len);
+        ret = blk_co_pdiscard(exp->common.blk, request->from, request->len, 0);
         if (ret >= 0 && request->flags & NBD_CMD_FLAG_FUA) {
             ret = blk_co_flush(exp->common.blk);
         }
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 13e0330162..f6d077908f 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -2201,7 +2201,7 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
     }
 
     clock_gettime(CLOCK_MONOTONIC, &t1);
-    ret = blk_pdiscard(blk, offset, bytes);
+    ret = blk_pdiscard(blk, offset, bytes, 0);
     clock_gettime(CLOCK_MONOTONIC, &t2);
 
     if (ret < 0) {
diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c
index e26b3be593..5273ff235a 100644
--- a/tests/unit/test-block-iothread.c
+++ b/tests/unit/test-block-iothread.c
@@ -270,11 +270,11 @@ static void test_sync_op_blk_pdiscard(BlockBackend *blk)
     int ret;
 
     /* Early success: UNMAP not supported */
-    ret = blk_pdiscard(blk, 0, 512);
+    ret = blk_pdiscard(blk, 0, 512, 0);
     g_assert_cmpint(ret, ==, 0);
 
     /* Early error: Negative offset */
-    ret = blk_pdiscard(blk, -2, 512);
+    ret = blk_pdiscard(blk, -2, 512, 0);
     g_assert_cmpint(ret, ==, -EIO);
 }
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 84/94] ide: Minimal fix for deadlock between TRIM and drain
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (24 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 83/94] block: Add flags parameter to blk_*_pdiscard() Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 85/94] ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code Michael Tokarev
                   ` (10 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

The implementation of TRIM in IDE can chain multiple discard requests
and uses blk_inc/dec_in_flight() to make sure that the whole TRIM
operation has completed when the device needs to be quiescent (e.g. for
the drain when performing an IDE reset, it would be bad if an IDE
request like TRIM were still in flight).

The problem is that each drain request calls blk_wait_while_drained()
and when draining, it waits until the drained section ends. At the same
time, drain_begin can only return if the whole TRIM operation has
completed. This is a classic deadlock.

Use blk_co_start/end_request() and BDRV_REQ_NO_QUEUE to avoid the
problem. This requires moving the TRIM state machine to a coroutine.
This commit does the minimal conversion so that we do have a coroutine
that works for the fix, but it still looks much like a callback-based
implementation. This will be cleaned up in the next patch.

Cc: qemu-stable@nongnu.org
Fixes: 7e5cdb345f77 ('ide: Increment BB in-flight counter for TRIM BH')
Buglink: https://redhat.atlassian.net/browse/RHEL-121686
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-5-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 095c08a7ba68cabaa6e0ce7a8a0804a949542c4c)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 7a15d6cac9..48359c934c 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -420,7 +420,6 @@ typedef struct TrimAIOCB {
     QEMUBH *bh;
     int ret;
     QEMUIOVector *qiov;
-    BlockAIOCB *aiocb;
     int i, j;
 } TrimAIOCB;
 
@@ -433,11 +432,6 @@ static void trim_aio_cancel(BlockAIOCB *acb)
     iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1;
 
     iocb->ret = -ECANCELED;
-
-    if (iocb->aiocb) {
-        blk_aio_cancel_async(iocb->aiocb);
-        iocb->aiocb = NULL;
-    }
 }
 
 static const AIOCBInfo trim_aiocb_info = {
@@ -456,15 +450,20 @@ static void ide_trim_bh_cb(void *opaque)
     iocb->bh = NULL;
     qemu_aio_unref(iocb);
 
-    /* Paired with an increment in ide_issue_trim() */
-    blk_dec_in_flight(blk);
+    /* Paired with blk_co_start_request in ide_trim_co_entry() */
+    blk_end_request(blk);
 }
 
-static void ide_issue_trim_cb(void *opaque, int ret)
+static void coroutine_fn ide_trim_co_entry(void *opaque)
 {
     TrimAIOCB *iocb = opaque;
     IDEState *s = iocb->s;
+    int ret = 0;
+
+    /* Paired with blk_end_request in ide_trim_bh_cb() */
+    blk_co_start_request(s->blk);
 
+loop:
     if (iocb->i >= 0) {
         if (ret >= 0) {
             block_acct_done(blk_get_stats(s->blk), &s->acct);
@@ -499,11 +498,11 @@ static void ide_issue_trim_cb(void *opaque, int ret)
                                  count << BDRV_SECTOR_BITS, BLOCK_ACCT_UNMAP);
 
                 /* Got an entry! Submit and exit.  */
-                iocb->aiocb = blk_aio_pdiscard(s->blk,
-                                               sector << BDRV_SECTOR_BITS,
-                                               count << BDRV_SECTOR_BITS,
-                                               ide_issue_trim_cb, opaque);
-                return;
+                ret = blk_co_pdiscard(s->blk,
+                                      sector << BDRV_SECTOR_BITS,
+                                      count << BDRV_SECTOR_BITS,
+                                      BDRV_REQ_NO_QUEUE);
+                goto loop;
             }
 
             iocb->j++;
@@ -514,7 +513,6 @@ static void ide_issue_trim_cb(void *opaque, int ret)
     }
 
 done:
-    iocb->aiocb = NULL;
     if (iocb->bh) {
         replay_bh_schedule_event(iocb->bh);
     }
@@ -527,9 +525,7 @@ BlockAIOCB *ide_issue_trim(
     IDEState *s = opaque;
     IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
     TrimAIOCB *iocb;
-
-    /* Paired with a decrement in ide_trim_bh_cb() */
-    blk_inc_in_flight(s->blk);
+    Coroutine *co;
 
     iocb = blk_aio_get(&trim_aiocb_info, s->blk, cb, cb_opaque);
     iocb->s = s;
@@ -539,7 +535,10 @@ BlockAIOCB *ide_issue_trim(
     iocb->qiov = qiov;
     iocb->i = -1;
     iocb->j = 0;
-    ide_issue_trim_cb(iocb, 0);
+
+    co = qemu_coroutine_create(ide_trim_co_entry, iocb);
+    aio_co_enter(qemu_get_current_aio_context(), co);
+
     return &iocb->common;
 }
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 85/94] ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (25 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 84/94] ide: Minimal fix for deadlock between TRIM and drain Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 86/94] ide-test: Factor out wait_dma_completion() Michael Tokarev
                   ` (9 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

The previous commit did a minimal conversion of the callback based state
machine for TRIM to a coroutine in order to fix a bug. Refactor it to
actually look like normal coroutine based code, which improves its
readability.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-6-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit c1c71a7e167fdabaa9827d00c0be3aeafebdd921)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 48359c934c..f78b00220b 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -420,18 +420,15 @@ typedef struct TrimAIOCB {
     QEMUBH *bh;
     int ret;
     QEMUIOVector *qiov;
-    int i, j;
+    bool canceled;
 } TrimAIOCB;
 
 static void trim_aio_cancel(BlockAIOCB *acb)
 {
     TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
 
-    /* Exit the loop so ide_issue_trim_cb will not continue  */
-    iocb->j = iocb->qiov->niov - 1;
-    iocb->i = (iocb->qiov->iov[iocb->j].iov_len / 8) - 1;
-
-    iocb->ret = -ECANCELED;
+    /* Exit the loop so ide_trim_co_entry will not continue */
+    iocb->canceled = true;
 }
 
 static const AIOCBInfo trim_aiocb_info = {
@@ -458,60 +455,55 @@ static void coroutine_fn ide_trim_co_entry(void *opaque)
 {
     TrimAIOCB *iocb = opaque;
     IDEState *s = iocb->s;
-    int ret = 0;
+    int i, j;
+    int ret;
 
     /* Paired with blk_end_request in ide_trim_bh_cb() */
     blk_co_start_request(s->blk);
 
-loop:
-    if (iocb->i >= 0) {
-        if (ret >= 0) {
-            block_acct_done(blk_get_stats(s->blk), &s->acct);
-        } else {
-            block_acct_failed(blk_get_stats(s->blk), &s->acct);
-        }
-    }
+    for (j = 0; j < iocb->qiov->niov; j++) {
+        for (i = 0; i < iocb->qiov->iov[j].iov_len / 8; i++) {
+            uint64_t *buffer = iocb->qiov->iov[j].iov_base;
 
-    if (ret >= 0) {
-        while (iocb->j < iocb->qiov->niov) {
-            int j = iocb->j;
-            while (++iocb->i < iocb->qiov->iov[j].iov_len / 8) {
-                int i = iocb->i;
-                uint64_t *buffer = iocb->qiov->iov[j].iov_base;
+            /* 6-byte LBA + 2-byte range per entry */
+            uint64_t entry = le64_to_cpu(buffer[i]);
+            uint64_t sector = entry & 0x0000ffffffffffffULL;
+            uint16_t count = entry >> 48;
 
-                /* 6-byte LBA + 2-byte range per entry */
-                uint64_t entry = le64_to_cpu(buffer[i]);
-                uint64_t sector = entry & 0x0000ffffffffffffULL;
-                uint16_t count = entry >> 48;
+            if (count == 0) {
+                continue;
+            }
 
-                if (count == 0) {
-                    continue;
-                }
+            if (iocb->canceled) {
+                iocb->ret = -ECANCELED;
+                goto done;
+            }
 
-                if (!ide_sect_range_ok(s, sector, count)) {
-                    block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_UNMAP);
-                    iocb->ret = -EINVAL;
-                    goto done;
-                }
+            if (!ide_sect_range_ok(s, sector, count)) {
+                block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_UNMAP);
+                iocb->ret = -EINVAL;
+                goto done;
+            }
 
-                block_acct_start(blk_get_stats(s->blk), &s->acct,
-                                 count << BDRV_SECTOR_BITS, BLOCK_ACCT_UNMAP);
+            block_acct_start(blk_get_stats(s->blk), &s->acct,
+                             count << BDRV_SECTOR_BITS, BLOCK_ACCT_UNMAP);
 
-                /* Got an entry! Submit and exit.  */
-                ret = blk_co_pdiscard(s->blk,
-                                      sector << BDRV_SECTOR_BITS,
-                                      count << BDRV_SECTOR_BITS,
-                                      BDRV_REQ_NO_QUEUE);
-                goto loop;
+            /* Got an entry! Submit and exit.  */
+            ret = blk_co_pdiscard(s->blk,
+                                  sector << BDRV_SECTOR_BITS,
+                                  count << BDRV_SECTOR_BITS,
+                                  BDRV_REQ_NO_QUEUE);
+            if (ret >= 0) {
+                block_acct_done(blk_get_stats(s->blk), &s->acct);
+            } else {
+                iocb->ret = ret;
+                block_acct_failed(blk_get_stats(s->blk), &s->acct);
+                goto done;
             }
-
-            iocb->j++;
-            iocb->i = -1;
         }
-    } else {
-        iocb->ret = ret;
     }
 
+    iocb->ret = 0;
 done:
     if (iocb->bh) {
         replay_bh_schedule_event(iocb->bh);
@@ -533,8 +525,7 @@ BlockAIOCB *ide_issue_trim(
                                    &DEVICE(dev)->mem_reentrancy_guard);
     iocb->ret = 0;
     iocb->qiov = qiov;
-    iocb->i = -1;
-    iocb->j = 0;
+    iocb->canceled = false;
 
     co = qemu_coroutine_create(ide_trim_co_entry, iocb);
     aio_co_enter(qemu_get_current_aio_context(), co);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 86/94] ide-test: Factor out wait_dma_completion()
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (26 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 85/94] ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 87/94] ide-test: Test reset during TRIM Michael Tokarev
                   ` (8 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-7-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 92854c9c7539bdbf4f9c1abb33dd3ba59ff91e58)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c
index ceee444a9e..c6dcb2c074 100644
--- a/tests/qtest/ide-test.c
+++ b/tests/qtest/ide-test.c
@@ -200,6 +200,34 @@ static uint64_t trim_range_le(uint64_t sector, uint16_t count)
     return cpu_to_le64(((uint64_t)count << 48) + sector);
 }
 
+static uint8_t wait_dma_completion(QTestState *qts, QPCIDevice *dev,
+                                   QPCIBar bmdma_bar, QPCIBar ide_bar)
+{
+    uint8_t status;
+
+    /* Wait for the DMA transfer to complete */
+    do {
+        status = qpci_io_readb(dev, bmdma_bar, bmreg_status);
+    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
+
+    g_assert_cmpint(qtest_get_irq(qts, IDE_PRIMARY_IRQ), ==,
+                    !!(status & BM_STS_INTR));
+
+    /* Check IDE status code */
+    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), DRDY);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), BSY | DRQ);
+
+    /* Reading the status register clears the IRQ */
+    g_assert(!qtest_get_irq(qts, IDE_PRIMARY_IRQ));
+
+    /* Stop DMA transfer if still active */
+    if (status & BM_STS_ACTIVE) {
+        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
+    }
+
+    return status;
+}
+
 static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
                             int nb_sectors, PrdtEntry *prdt, int prdt_entries,
                             void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
@@ -280,25 +308,7 @@ static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
         qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
     }
 
-    /* Wait for the DMA transfer to complete */
-    do {
-        status = qpci_io_readb(dev, bmdma_bar, bmreg_status);
-    } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
-
-    g_assert_cmpint(qtest_get_irq(qts, IDE_PRIMARY_IRQ), ==,
-                    !!(status & BM_STS_INTR));
-
-    /* Check IDE status code */
-    assert_bit_set(qpci_io_readb(dev, ide_bar, reg_status), DRDY);
-    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), BSY | DRQ);
-
-    /* Reading the status register clears the IRQ */
-    g_assert(!qtest_get_irq(qts, IDE_PRIMARY_IRQ));
-
-    /* Stop DMA transfer if still active */
-    if (status & BM_STS_ACTIVE) {
-        qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
-    }
+    status = wait_dma_completion(qts, dev, bmdma_bar, ide_bar);
 
     free_pci_device(dev);
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 87/94] ide-test: Test reset during TRIM
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (27 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 86/94] ide-test: Factor out wait_dma_completion() Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 88/94] block: Create DEFAULT_BLOCK_CONF macro Michael Tokarev
                   ` (7 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

This is a regression test for the bug fixed in the previous commits, a
deadlock between the drain issued by an IDE reset and the TRIM state
machine.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260421161132.99878-8-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 2fa24e9755994f76f08ea2452215eb50f26f4c21)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/tests/qtest/ide-test.c b/tests/qtest/ide-test.c
index c6dcb2c074..721e78170b 100644
--- a/tests/qtest/ide-test.c
+++ b/tests/qtest/ide-test.c
@@ -41,8 +41,11 @@
 #define IDE_PCI_FUNC    1
 
 #define IDE_BASE 0x1f0
+#define IDE_BASE2 0x3f6
 #define IDE_PRIMARY_IRQ 14
 
+#define IDE_CTRL_RESET 0x04
+
 #define ATAPI_BLOCK_SIZE 2048
 
 /* How many bytes to receive via ATAPI PIO at one time.
@@ -99,6 +102,7 @@ enum {
 
     CMDF_ABORT      = 0x100,
     CMDF_NO_BM      = 0x200,
+    CMDF_NO_WAIT    = 0x400,
 };
 
 enum {
@@ -228,21 +232,21 @@ static uint8_t wait_dma_completion(QTestState *qts, QPCIDevice *dev,
     return status;
 }
 
-static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
-                            int nb_sectors, PrdtEntry *prdt, int prdt_entries,
-                            void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
-                                             uint64_t sector, int nb_sectors))
+static int send_dma_request_dev(QTestState *qts, QPCIDevice *dev,
+                                QPCIBar bmdma_bar, QPCIBar ide_bar, int cmd,
+                                uint64_t sector, int nb_sectors,
+                                PrdtEntry *prdt, int prdt_entries,
+                                void(*post_exec)(QPCIDevice *dev,
+                                                 QPCIBar ide_bar,
+                                                 uint64_t sector,
+                                                 int nb_sectors))
 {
-    QPCIDevice *dev;
-    QPCIBar bmdma_bar, ide_bar;
     uintptr_t guest_prdt;
     size_t len;
     bool from_dev;
     uint8_t status;
     int flags;
 
-    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
-
     flags = cmd & ~0xff;
     cmd &= 0xff;
 
@@ -308,8 +312,28 @@ static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
         qpci_io_writeb(dev, bmdma_bar, bmreg_cmd, 0);
     }
 
+    if (flags & CMDF_NO_WAIT) {
+        return 0;
+    }
+
     status = wait_dma_completion(qts, dev, bmdma_bar, ide_bar);
 
+    return status;
+}
+
+static int send_dma_request(QTestState *qts, int cmd, uint64_t sector,
+                            int nb_sectors, PrdtEntry *prdt, int prdt_entries,
+                            void(*post_exec)(QPCIDevice *dev, QPCIBar ide_bar,
+                                             uint64_t sector, int nb_sectors))
+{
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar;
+    uint8_t status;
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+    status = send_dma_request_dev(qts, dev, bmdma_bar, ide_bar,
+                                  cmd, sector, nb_sectors, prdt, prdt_entries,
+                                  post_exec);
     free_pci_device(dev);
 
     return status;
@@ -457,6 +481,60 @@ static void test_bmdma_trim(void)
     test_bmdma_teardown(qts);
 }
 
+static void test_bmdma_trim_reset(void)
+{
+    QTestState *qts;
+    QPCIDevice *dev;
+    QPCIBar bmdma_bar, ide_bar, ide_bar2;
+    uint8_t status;
+    const uint64_t trim_range[] = {
+        trim_range_le(0, 2),
+        trim_range_le(6, 8),
+    };
+    size_t len = 512;
+    uint8_t *buf;
+    uintptr_t guest_buf;
+    PrdtEntry prdt[1];
+
+    qts = ide_test_start(
+        "-blockdev file,filename=%s,node-name=img "
+        "-blockdev blkdebug,image=img,node-name=dbg,discard=unmap,"
+        "inject-error.0.event=none,inject-error.0.iotype=discard,"
+        "inject-error.0.errno=0,inject-error.0.delay-ns=1000000 "
+        "-device ide-hd,drive=dbg,bus=ide.0",
+        tmp_path[0]);
+    qtest_irq_intercept_in(qts, "ioapic");
+
+    guest_buf = guest_alloc(&guest_malloc, len);
+    prdt[0].addr = cpu_to_le32(guest_buf),
+    prdt[0].size = cpu_to_le32(len | PRDT_EOT),
+
+    dev = get_pci_device(qts, &bmdma_bar, &ide_bar);
+    ide_bar2 = qpci_legacy_iomap(dev, IDE_BASE2);
+
+    buf = g_malloc(len);
+
+    /* TRIM request with two segments */
+    *((uint64_t *)buf) = trim_range[0];
+    *((uint64_t *)buf + 1) = trim_range[1];
+
+    qtest_memwrite(qts, guest_buf, buf, 2 * sizeof(uint64_t));
+
+    send_dma_request_dev(qts, dev, bmdma_bar, ide_bar, CMD_DSM | CMDF_NO_WAIT, 0, 1, prdt,
+                     ARRAY_SIZE(prdt), NULL);
+
+    /* Reset the device while the first segment is in flight */
+    qpci_io_writeb(dev, ide_bar2, 0, IDE_CTRL_RESET);
+
+    status = wait_dma_completion(qts, dev, bmdma_bar, ide_bar);
+    g_assert_cmphex(status, ==, BM_STS_INTR);
+    assert_bit_clear(qpci_io_readb(dev, ide_bar, reg_status), DF | ERR);
+
+    free_pci_device(dev);
+    g_free(buf);
+    test_bmdma_teardown(qts);
+}
+
 /*
  * This test is developed according to the Programming Interface for
  * Bus Master IDE Controller (Revision 1.0 5/16/94)
@@ -1138,6 +1216,7 @@ int main(int argc, char **argv)
 
     qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
     qtest_add_func("/ide/bmdma/trim", test_bmdma_trim);
+    qtest_add_func("/ide/bmdma/trim_reset", test_bmdma_trim_reset);
     qtest_add_func("/ide/bmdma/various_prdts", test_bmdma_various_prdts);
     qtest_add_func("/ide/bmdma/no_busmaster", test_bmdma_no_busmaster);
 
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 88/94] block: Create DEFAULT_BLOCK_CONF macro
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (28 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 87/94] ide-test: Test reset during TRIM Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 89/94] block: Add more defaults to DEFAULT_BLOCK_CONF Michael Tokarev
                   ` (6 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

The property default values from include/hw/block/block.h were
duplicated in scsi_bus_legacy_handle_cmdline(), allowing them to go out
of sync easily. There doesn't seem a good way to avoid the duplication,
but moving them next to each other in the header file should help to
avoid this problem in the future.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260410152314.86412-2-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit a1310cc6281d22ac948f4aa198dcc55d58fc039d)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 1a6b181b9d..dccb2f25b2 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -485,12 +485,7 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
     Location loc;
     DriveInfo *dinfo;
     int unit;
-    BlockConf conf = {
-        .bootindex = -1,
-        .share_rw = false,
-        .rerror = BLOCKDEV_ON_ERROR_AUTO,
-        .werror = BLOCKDEV_ON_ERROR_AUTO,
-    };
+    BlockConf conf = DEFAULT_BLOCK_CONF;
 
     loc_push_none(&loc);
     for (unit = 0; unit <= bus->info->max_target; unit++) {
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
index 7dc19d8a45..e0a427039e 100644
--- a/include/hw/block/block.h
+++ b/include/hw/block/block.h
@@ -51,6 +51,13 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
     return exp;
 }
 
+#define DEFAULT_BLOCK_CONF (BlockConf) {                                \
+    .bootindex = -1,                                                    \
+    .share_rw = false,                                                  \
+    .rerror = BLOCKDEV_ON_ERROR_AUTO,                                   \
+    .werror = BLOCKDEV_ON_ERROR_AUTO,                                   \
+}
+
 #define DEFINE_BLOCK_PROPERTIES_BASE(_state, _conf)                     \
     DEFINE_PROP_ON_OFF_AUTO("backend_defaults", _state,                 \
                             _conf.backend_defaults, ON_OFF_AUTO_AUTO),  \
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 89/94] block: Add more defaults to DEFAULT_BLOCK_CONF
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (29 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 88/94] block: Create DEFAULT_BLOCK_CONF macro Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 90/94] commit: Drain nodes across all of bdrv_commit() Michael Tokarev
                   ` (5 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Lexi Winter, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

discard_granularity was missing from this, which means that SCSI disks
created with -drive if=scsi would default to 0 (i.e. disabling discards)
instead of -1, which makes scsi-hd automatically pick a granularity and
is the default of the corresponding qdev property for -device scsi-hd.

This was broken in QEMU 9.0 with commit 3089637.

Also set other fields whose default isn't an obvious 0. These are not
actual bug fixes because ON_OFF_AUTO_AUTO in fact happens to be 0, but
it's better not to rely on the order of enums.

Cc: qemu-stable@nongnu.org
Fixes: 308963746169 ('scsi: Don't ignore most usb-storage properties')
Reported-by: Lexi Winter <ivy@FreeBSD.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260410152314.86412-3-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit f27aea1896338f4dd085a0e2cb2ab3797c5fe3e9)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/include/hw/block/block.h b/include/hw/block/block.h
index e0a427039e..df941df19f 100644
--- a/include/hw/block/block.h
+++ b/include/hw/block/block.h
@@ -53,7 +53,12 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
 
 #define DEFAULT_BLOCK_CONF (BlockConf) {                                \
     .bootindex = -1,                                                    \
+    .backend_defaults = ON_OFF_AUTO_AUTO,                               \
+    .discard_granularity = -1,                                          \
+    .wce = ON_OFF_AUTO_AUTO,                                            \
     .share_rw = false,                                                  \
+    .account_invalid = ON_OFF_AUTO_AUTO,                                \
+    .account_failed = ON_OFF_AUTO_AUTO,                                 \
     .rerror = BLOCKDEV_ON_ERROR_AUTO,                                   \
     .werror = BLOCKDEV_ON_ERROR_AUTO,                                   \
 }
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 90/94] commit: Drain nodes across all of bdrv_commit()
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (30 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 89/94] block: Add more defaults to DEFAULT_BLOCK_CONF Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 91/94] qemu-io: Add 'aio_discard' command Michael Tokarev
                   ` (4 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Denis V. Lunev, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

The whole implementation of bdrv_commit() is only correct if no new
writes come in while it's running: It has only a single loop checking
the allocation status for each block and finally calls bdrv_make_empty()
without checking if that throws away any new changes.

We already have to drain while taking the graph write lock. Just extend
the drained section to all of bdrv_commit() to make sure that we don't
get any inconsistencies.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260427170520.101242-2-kwolf@redhat.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Tested-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit f0d9ccd46cf8fc576ab7d514f10f766546cdbc14)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/block/commit.c b/block/commit.c
index 0d9e1a16d7..c5e3ef03a2 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -518,6 +518,7 @@ int bdrv_commit(BlockDriverState *bs)
     if (!drv)
         return -ENOMEDIUM;
 
+    bdrv_drain_all_begin();
     bdrv_graph_rdlock_main_loop();
 
     backing_file_bs = bdrv_cow_bs(bs);
@@ -549,6 +550,10 @@ int bdrv_commit(BlockDriverState *bs)
                   BLK_PERM_ALL);
     backing = blk_new(ctx, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
 
+    /* We drained all nodes, but still make requests through BlockBackends */
+    blk_set_disable_request_queuing(src, true);
+    blk_set_disable_request_queuing(backing, true);
+
     ret = blk_insert_bs(src, bs, &local_err);
     if (ret < 0) {
         error_report_err(local_err);
@@ -565,7 +570,7 @@ int bdrv_commit(BlockDriverState *bs)
 
     bdrv_graph_rdunlock_main_loop();
 
-    bdrv_graph_wrlock_drained();
+    bdrv_graph_wrlock();
     bdrv_set_backing_hd(commit_top_bs, backing_file_bs, &error_abort);
     bdrv_set_backing_hd(bs, commit_top_bs, &error_abort);
     bdrv_graph_wrunlock();
@@ -647,7 +652,7 @@ ro_cleanup:
     blk_unref(backing);
 
     bdrv_graph_rdunlock_main_loop();
-    bdrv_graph_wrlock_drained();
+    bdrv_graph_wrlock();
     if (bdrv_cow_bs(bs) != backing_file_bs) {
         bdrv_set_backing_hd(bs, backing_file_bs, &error_abort);
     }
@@ -663,6 +668,7 @@ ro_cleanup:
 
 out:
     bdrv_graph_rdunlock_main_loop();
+    bdrv_drain_all_end();
 
     return ret;
 }
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 91/94] qemu-io: Add 'aio_discard' command
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (31 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 90/94] commit: Drain nodes across all of bdrv_commit() Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 92/94] qcow2: Fix corruption on discard during write with COW Michael Tokarev
                   ` (3 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Denis V. Lunev, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

Testing interactions between multiple requests that include discard
requests require that qemu-io can do the discard asynchronously, like it
already does for reads and writes. To this effect, add an 'aio_discard'
command.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260427170520.101242-3-kwolf@redhat.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Tested-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 7f8466e2ce620e3c6a6e2f32d616367174d4dbe9)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index f6d077908f..de4c1966fe 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -2218,6 +2218,120 @@ static int discard_f(BlockBackend *blk, int argc, char **argv)
     return 0;
 }
 
+static void aio_discard_help(void)
+{
+    printf(
+"\n"
+" asynchronously discards a range of bytes from the given offset\n"
+"\n"
+" Example:\n"
+" 'aio_discard 512 1k' - discards 1 kilobyte from 512 bytes into the file\n"
+"\n"
+" Discards a segment of the currently open file.\n"
+" -C, -- report statistics in a machine parsable format\n"
+" -q, -- quiet mode, do not show I/O statistics\n"
+" The discard is performed asynchronously and the aio_flush command must be\n"
+" used to ensure all outstanding aio requests have been completed.\n"
+" Note that due to its asynchronous nature, this command will be\n"
+" considered successful once the request is submitted, independently\n"
+" of potential I/O errors.\n"
+"\n");
+}
+
+static int aio_discard_f(BlockBackend *blk, int argc, char **argv);
+
+static const cmdinfo_t aio_discard_cmd = {
+    .name       = "aio_discard",
+    .cfunc      = aio_discard_f,
+    .perm       = BLK_PERM_WRITE,
+    .argmin     = 2,
+    .argmax     = -1,
+    .args       = "[-Cq] off len",
+    .oneline    = "asynchronously discards a number of bytes",
+    .help       = aio_discard_help,
+};
+
+static void aio_discard_done(void *opaque, int ret)
+{
+    struct aio_ctx *ctx = opaque;
+    struct timespec t2;
+
+    clock_gettime(CLOCK_MONOTONIC, &t2);
+
+    if (ret < 0) {
+        printf("aio_discard failed: %s\n", strerror(-ret));
+        block_acct_failed(blk_get_stats(ctx->blk), &ctx->acct);
+        goto out;
+    }
+
+    block_acct_done(blk_get_stats(ctx->blk), &ctx->acct);
+
+    if (ctx->qflag) {
+        goto out;
+    }
+
+    /* Finally, report back -- -C gives a parsable format */
+    t2 = tsub(t2, ctx->t1);
+    print_report("discarded ", &t2, ctx->offset, ctx->qiov.size,
+                 ctx->qiov.size, 1, ctx->Cflag);
+out:
+    g_free(ctx);
+}
+
+static int aio_discard_f(BlockBackend *blk, int argc, char **argv)
+{
+    int c, ret;
+    int64_t count;
+    struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
+
+    ctx->blk = blk;
+
+    while ((c = getopt(argc, argv, "Cq")) != -1) {
+        switch (c) {
+        case 'C':
+            ctx->Cflag = true;
+            break;
+        case 'q':
+            ctx->qflag = true;
+            break;
+        default:
+            g_free(ctx);
+            qemuio_command_usage(&aio_discard_cmd);
+            return -EINVAL;
+        }
+    }
+
+    if (optind != argc - 2) {
+        g_free(ctx);
+        qemuio_command_usage(&aio_discard_cmd);
+        return -EINVAL;
+    }
+
+    ctx->offset = cvtnum(argv[optind]);
+    if (ctx->offset < 0) {
+        ret = ctx->offset;
+        print_cvtnum_err(ret, argv[optind]);
+        g_free(ctx);
+        return ret;
+    }
+    optind++;
+
+    count = cvtnum(argv[optind]);
+    if (count < 0) {
+        print_cvtnum_err(count, argv[optind]);
+        g_free(ctx);
+        return count;
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
+    ctx->qiov.size = count;
+    block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
+                     BLOCK_ACCT_UNMAP);
+    blk_aio_pdiscard(blk, ctx->offset, count, aio_discard_done, ctx);
+
+    return 0;
+}
+
 static int alloc_f(BlockBackend *blk, int argc, char **argv)
 {
     BlockDriverState *bs = blk_bs(blk);
@@ -2800,6 +2914,7 @@ static void __attribute((constructor)) init_qemuio_commands(void)
     qemuio_add_command(&length_cmd);
     qemuio_add_command(&info_cmd);
     qemuio_add_command(&discard_cmd);
+    qemuio_add_command(&aio_discard_cmd);
     qemuio_add_command(&alloc_cmd);
     qemuio_add_command(&map_cmd);
     qemuio_add_command(&reopen_cmd);
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 92/94] qcow2: Fix corruption on discard during write with COW
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (32 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 91/94] qemu-io: Add 'aio_discard' command Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 93/94] iotests/046: Test that discard/write_zeroes wait for dependencies Michael Tokarev
                   ` (2 subsequent siblings)
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Denis V. Lunev, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

Most code in qcow2 that accesses (and potentially modifies) L2 tables
does so while holding s->lock.

There is one exception, which is allocating writes. They hold the lock
initially while allocating clusters, but drop it for writing the guest
payload before taking the lock again for updating the L2 tables. This
allows concurrent requests that touch other parts of the image file to
continue in parallel and is an important performance optimisation.

However, this means that other requests that run while the lock is
dropped for writing guest data must synchronise with the list of
allocating requests in s->cluster_allocs and wait if they would overlap.
For writes, this is done in handle_dependencies(), but discard and write
zeros operations neglect to synchronise with s->cluster_allocs.

This means that discard can free a cluster whose L2 entry will already
be modified in qcow2_alloc_cluster_link_l2() by a previously started
write. In the case of a pre-allocated zero cluster that is in the
process of being overwritten, this means that discard can lead to a
situation where the cluster is still mapped (because the write will
restore the L2 entry just without the zero flag), but its refcount has
been decreased, resulting in a corrupted image.

Add the missing synchronisation to qcow2_cluster_discard() and
qcow2_subcluster_zeroize() to fix the problem.

Cc: qemu-stable@nongnu.org
Reported-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260427170520.101242-4-kwolf@redhat.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Tested-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit b8bfb1478d61512f851badd0d912c6661a2efee7)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index c655bf6df4..8b1e80bd0b 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1392,6 +1392,9 @@ count_single_write_clusters(BlockDriverState *bs, int nb_clusters,
  * the same cluster. In this case we need to wait until the previous
  * request has completed and updated the L2 table accordingly.
  *
+ * If allow_shortening == true, instead of waiting for a dependency, *cur_bytes
+ * can be shortened so that the cluster allocations don't overlap.
+ *
  * Returns:
  *   0       if there was no dependency. *cur_bytes indicates the number of
  *           bytes from guest_offset that can be read before the next
@@ -1403,7 +1406,9 @@ count_single_write_clusters(BlockDriverState *bs, int nb_clusters,
  */
 static int coroutine_fn handle_dependencies(BlockDriverState *bs,
                                             uint64_t guest_offset,
-                                            uint64_t *cur_bytes, QCowL2Meta **m)
+                                            uint64_t *cur_bytes,
+                                            bool allow_shortening,
+                                            QCowL2Meta **m)
 {
     BDRVQcow2State *s = bs->opaque;
     QCowL2Meta *old_alloc;
@@ -1434,7 +1439,7 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,
 
         /* Conflict */
 
-        if (start < old_start) {
+        if (start < old_start && allow_shortening) {
             /* Stop at the start of a running allocation */
             bytes = old_start - start;
         } else {
@@ -1469,6 +1474,29 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,
     return 0;
 }
 
+static void coroutine_mixed_fn wait_for_dependencies(BlockDriverState *bs,
+                                                     uint64_t guest_offset,
+                                                     uint64_t bytes)
+{
+    BDRVQcow2State *s = bs->opaque;
+    QCowL2Meta *m = NULL;
+    int ret;
+
+    /*
+     * Discard has some non-coroutine callers (creating internal snapshots and
+     * make empty). They are calling from qemu-img or in a drained section, so
+     * we know that no writes can be in progress.
+     */
+    if (!qemu_in_coroutine()) {
+        assert(QLIST_EMPTY(&s->cluster_allocs));
+        return;
+    }
+
+    do {
+        ret = handle_dependencies(bs, guest_offset, &bytes, false, &m);
+    } while (ret == -EAGAIN);
+}
+
 /*
  * Checks how many already allocated clusters that don't require a new
  * allocation there are at the given guest_offset (up to *bytes).
@@ -1840,7 +1868,7 @@ again:
          *         the right synchronisation between the in-flight request and
          *         the new one.
          */
-        ret = handle_dependencies(bs, start, &cur_bytes, m);
+        ret = handle_dependencies(bs, start, &cur_bytes, true, m);
         if (ret == -EAGAIN) {
             /* Currently handle_dependencies() doesn't yield if we already had
              * an allocation. If it did, we would have to clean up the L2Meta
@@ -2000,6 +2028,15 @@ int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset,
     int64_t cleared;
     int ret;
 
+    /*
+     * If we're touching a cluster for which allocating writes are in flight,
+     * wait for them to complete to avoid conflicting metadata updates.
+     *
+     * We don't need to allocate a QCowL2Meta for the discard operation because
+     * s->lock is held for the duration of the whole operation.
+     */
+    wait_for_dependencies(bs, offset, bytes);
+
     /* Caller must pass aligned values, except at image end */
     assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
     assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
@@ -2160,6 +2197,15 @@ int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset,
     int64_t cleared;
     int ret;
 
+    /*
+     * If we're touching a cluster for which allocating writes are in flight,
+     * wait for them to complete to avoid conflicting metadata updates.
+     *
+     * We don't need to allocate a QCowL2Meta for the zeroize operation because
+     * s->lock is held for the duration of the whole operation.
+     */
+    wait_for_dependencies(bs, offset, bytes);
+
     /* If we have to stay in sync with an external data file, zero out
      * s->data_file first. */
     if (data_file_is_raw(bs)) {
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 93/94] iotests/046: Test that discard/write_zeroes wait for dependencies
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (33 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 92/94] qcow2: Fix corruption on discard during write with COW Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 21:33 ` [Stable-11.0.1 94/94] block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock() Michael Tokarev
  2026-05-22 23:10 ` [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Fiona Ebner
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, Kevin Wolf, Denis V. Lunev, Michael Tokarev

From: Kevin Wolf <kwolf@redhat.com>

This is a regression test for the bug fixed in the previous commit where
discard and write_zeroes operations wouldn't consider their dependencies
in s->cluster_allocs. Without the fix, this results in a corrupted
image.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20260427170520.101242-5-kwolf@redhat.com>
Reviewed-by: Denis V. Lunev <den@openvz.org>
Tested-by: Denis V. Lunev <den@openvz.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 389f5bcc744d3ddc127d550a57261aed9bbba1f3)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
index 4c9ed4d26e..e03dd40147 100755
--- a/tests/qemu-iotests/046
+++ b/tests/qemu-iotests/046
@@ -184,6 +184,48 @@ aio_write -P 160 0x104000 0x18000
 resume A
 aio_flush
 EOF
+
+# Create a pre-allocated zero cluster, then start a write on it and discard it
+# before the L2 update is made
+cat  <<EOF
+write -P 181 0x120000 0x10000
+write -z 0x120000 0x10000
+
+break write_aio A
+aio_write -P 180 0x120000 0x10000
+wait_break A
+aio_discard 0x120000 0x10000
+resume A
+aio_flush
+EOF
+
+# Create a pre-allocated zero cluster, then start a write on it and a
+# concurrent zero write with MAY_UNMAP before the L2 update is made
+cat  <<EOF
+write -P 181 0x130000 0x10000
+write -z 0x130000 0x10000
+
+break write_aio A
+aio_write -P 180 0x130000 0x10000
+wait_break A
+aio_write -z -u 0x130000 0x10000
+resume A
+aio_flush
+EOF
+
+# Create a pre-allocated zero cluster, then start a write on it and a
+# concurrent zero write without MAY_UNMAP before the L2 update is made
+cat  <<EOF
+write -P 181 0x140000 0x10000
+write -z 0x140000 0x10000
+
+break write_aio A
+aio_write -P 180 0x140000 0x10000
+wait_break A
+aio_write -z 0x140000 0x10000
+resume A
+aio_flush
+EOF
 }
 
 overlay_io | $QEMU_IO blkdebug::"$TEST_IMG" | _filter_qemu_io |\
@@ -264,6 +306,10 @@ verify_io()
     # Undefined content for 0x10c000 0x8000
     echo read -P 160 0x114000 0x8000
     echo read -P 17  0x11c000 0x4000
+
+    echo read -P 0   0x120000 0x10000
+    echo read -P 0   0x130000 0x10000
+    echo read -P 0   0x140000 0x10000
 }
 
 verify_io | $QEMU_IO "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/046.out b/tests/qemu-iotests/046.out
index b1a03f4041..6341df335c 100644
--- a/tests/qemu-iotests/046.out
+++ b/tests/qemu-iotests/046.out
@@ -139,6 +139,36 @@ wrote XXX/XXX bytes at offset XXX
 XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 wrote XXX/XXX bytes at offset XXX
 XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+blkdebug: Suspended request 'A'
+blkdebug: Resuming request 'A'
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+discarded  XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+blkdebug: Suspended request 'A'
+blkdebug: Resuming request 'A'
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+blkdebug: Suspended request 'A'
+blkdebug: Resuming request 'A'
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote XXX/XXX bytes at offset XXX
+XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
 == Verify image content ==
 read 65536/65536 bytes at offset 0
@@ -239,5 +269,11 @@ read 32768/32768 bytes at offset 1130496
 32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 read 16384/16384 bytes at offset 1163264
 16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 1179648
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 1245184
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 1310720
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 No errors were found on the image.
 *** done
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [Stable-11.0.1 94/94] block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock()
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (34 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 93/94] iotests/046: Test that discard/write_zeroes wait for dependencies Michael Tokarev
@ 2026-05-22 21:33 ` Michael Tokarev
  2026-05-22 23:10 ` [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Fiona Ebner
  36 siblings, 0 replies; 42+ messages in thread
From: Michael Tokarev @ 2026-05-22 21:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-stable, Denis V. Lunev, Kevin Wolf, Hanna Reitz,
	Stefan Hajnoczi, Fiona Ebner, Michael Tokarev

From: "Denis V. Lunev" <den@openvz.org>

tests/qemu-iotests/tests/iothreads-create reproduces the hang on
master under `stress-ng --cpu $(nproc) --timeout 0`.  The iotest's
vm.run_job() times out and qemu stays permanently stuck in
ppoll(timeout=-1) inside bdrv_graph_wrlock_drained -> blk_remove_bs
during qemu_cleanup().  The timing window is narrow on modern
bare-metal hardware and much wider in a VM guest; downstream trees
that still use plain bdrv_graph_wrlock() in blk_remove_bs() hit it
on the first iteration under the same stress.

bdrv_graph_wrlock() zeroes has_writer around its AIO_WAIT_WHILE loop
so that callbacks dispatched by aio_poll() can still take the read
lock on the fast path.  The rdunlock side, however, only kicks a
waiting writer when has_writer is observed set; a reader that drops
its lock inside the polling window silently returns and nothing ever
wakes the writer:

  main thread                         iothread0 coroutine
  -----------                         -------------------
  bdrv_graph_wrlock:                  rdlock held, reader_count=1
    bdrv_drain_all_begin_nopoll
    has_writer = 0
    AIO_WAIT_WHILE_UNLOCKED(
        NULL, reader_count >= 1):
      num_waiters++
      smp_mb
      aio_poll(main_ctx, true)   -->  bdrv_graph_co_rdunlock:
        (ppoll, blocked)                reader_count-- -> 0
                                        smp_mb
                                        read has_writer = 0
                                        skip aio_wait_kick()
                                      return

reader_count is now 0 and num_waiters is still 1, but no BH, fd or
timer on the main AioContext will fire -- the only entity that could
kick just decided it did not have to.  Main stays in ppoll() holding
BQL, so RCU, VCPUs and any iothread path that needs BQL stall behind
it.  The hang is final; no timeout, no forward progress, no recovery
as there is no other source of wake up inside qemu_cleanup().

bdrv_drain_all_begin() does not close the race on its own: it
quiesces in-flight I/O, but graph readers also include non-I/O
coroutines (block-job cleanup, virtio-scsi polling) that drain does
not evict.  The bdrv_graph_wrlock_drained() wrapper narrows the
window but does not eliminate it; every plain bdrv_graph_wrlock()
site is exposed on the same basis.

Drop the has_writer check in bdrv_graph_co_rdunlock() and call
aio_wait_kick() unconditionally.  The helper itself loads num_waiters
atomically and only schedules a dummy BH when a waiter exists, so the
change is a no-op on the no-writer path and closes the missed-wakeup
on the writer path.

Signed-off-by: Denis V. Lunev <den@openvz.org>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Hanna Reitz <hreitz@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Fiona Ebner <f.ebner@proxmox.com>
Message-ID: <20260424103917.248668-2-den@openvz.org>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit e3082ab3b38538ebdbc5cd62b4c476b673c5e515)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>

diff --git a/block/graph-lock.c b/block/graph-lock.c
index b7319473a1..f2501d75fb 100644
--- a/block/graph-lock.c
+++ b/block/graph-lock.c
@@ -278,14 +278,12 @@ void coroutine_fn bdrv_graph_co_rdunlock(void)
     smp_mb();
 
     /*
-     * has_writer == 0: this means reader will read reader_count decreased
-     * has_writer == 1: we don't know if writer read reader_count old or
-     *                  new. Therefore, kick again so on next iteration
-     *                  writer will for sure read the updated value.
+     * Always kick: bdrv_graph_wrlock() zeroes has_writer while polling (to
+     * let callbacks take the reader lock via the fast path), so we cannot
+     * rely on has_writer to detect a waiting writer. aio_wait_kick() is a
+     * no-op when no one is waiting, so it is cheap in the common case.
      */
-    if (qatomic_read(&has_writer)) {
-        aio_wait_kick();
-    }
+    aio_wait_kick();
 }
 
 void bdrv_graph_rdlock_main_loop(void)
-- 
2.47.3



^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen)
  2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
                   ` (35 preceding siblings ...)
  2026-05-22 21:33 ` [Stable-11.0.1 94/94] block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock() Michael Tokarev
@ 2026-05-22 23:10 ` Fiona Ebner
  2026-05-23  6:49   ` Michael Tokarev
  36 siblings, 1 reply; 42+ messages in thread
From: Fiona Ebner @ 2026-05-22 23:10 UTC (permalink / raw)
  To: Michael Tokarev; +Cc: qemu-stable, Kevin Wolf, qemu-devel

Hi Michael,

Am 22.05.26 um 11:35 PM schrieb Michael Tokarev:
> Please respond here or CC qemu-stable@nongnu.org on any additional patches
> you think should (or shouldn't) be included in the release.

> 92 b8bfb1478d61 Kevin Wolf:
>    qcow2: Fix corruption on discard during write with COW
> 93 389f5bcc744d Kevin Wolf:
>    iotests/046: Test that discard/write_zeroes wait for dependencies

since number 92 can cause an issue [0] that is much easier to run into
than the one it solves, but still similarly bad, I think it should only
be included together with Thomas' fix [1] on top. I know that one has
not been applied to master or reviewed by a maintainer yet, so if
including it goes against procedure, maybe it'd be better to leave 92
(and 93) out for now or delay the release?

Same for the other stable series. Thank you for the consideration!

Best Regards,
Fiona

[0]:
https://lore.kernel.org/qemu-devel/414848c6-3829-4120-b760-6db8d43c1ab5@proxmox.com/
[1]:
https://lore.kernel.org/qemu-devel/20260522151318.238064-1-t.lamprecht@proxmox.com/




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen)
  2026-05-22 23:10 ` [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Fiona Ebner
@ 2026-05-23  6:49   ` Michael Tokarev
  2026-05-26 18:07     ` Kevin Wolf
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Tokarev @ 2026-05-23  6:49 UTC (permalink / raw)
  To: Fiona Ebner; +Cc: qemu-stable, Kevin Wolf, qemu-devel

On 23.05.2026 02:10, Fiona Ebner wrote:
> Hi Michael,
> 
> Am 22.05.26 um 11:35 PM schrieb Michael Tokarev:
>> Please respond here or CC qemu-stable@nongnu.org on any additional patches
>> you think should (or shouldn't) be included in the release.
> 
>> 92 b8bfb1478d61 Kevin Wolf:
>>     qcow2: Fix corruption on discard during write with COW
>> 93 389f5bcc744d Kevin Wolf:
>>     iotests/046: Test that discard/write_zeroes wait for dependencies
> 
> since number 92 can cause an issue [0] that is much easier to run into
> than the one it solves, but still similarly bad, I think it should only
> be included together with Thomas' fix [1] on top. I know that one has
> not been applied to master or reviewed by a maintainer yet, so if
> including it goes against procedure, maybe it'd be better to leave 92
> (and 93) out for now or delay the release?
> 
> Same for the other stable series. Thank you for the consideration!

Thank you very much for letting me know.  Yes, it isn't good to include
"Fix corruption on discard" without the follow-up fix.  So it would be
very nice to have the follow-up fix applied to the master branch today
or tomorrow (this is Sat and Sun, maybe not the best timing), or I'll
have to drop the above mentioned two changes from the stable series.
Or indeed, releases should be delayed - in a hope the fix can be applied
on Monday.

I'll wait for some reaction.  Kevin?

Thanks,

/mjt

> [0]:
> https://lore.kernel.org/qemu-devel/414848c6-3829-4120-b760-6db8d43c1ab5@proxmox.com/
> [1]:
> https://lore.kernel.org/qemu-devel/20260522151318.238064-1-t.lamprecht@proxmox.com/
> 
> 
> 



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen)
  2026-05-23  6:49   ` Michael Tokarev
@ 2026-05-26 18:07     ` Kevin Wolf
  2026-05-26 18:09       ` Michael Tokarev
  0 siblings, 1 reply; 42+ messages in thread
From: Kevin Wolf @ 2026-05-26 18:07 UTC (permalink / raw)
  To: Michael Tokarev; +Cc: Fiona Ebner, qemu-stable, qemu-devel

Am 23.05.2026 um 08:49 hat Michael Tokarev geschrieben:
> On 23.05.2026 02:10, Fiona Ebner wrote:
> > Hi Michael,
> > 
> > Am 22.05.26 um 11:35 PM schrieb Michael Tokarev:
> > > Please respond here or CC qemu-stable@nongnu.org on any additional patches
> > > you think should (or shouldn't) be included in the release.
> > 
> > > 92 b8bfb1478d61 Kevin Wolf:
> > >     qcow2: Fix corruption on discard during write with COW
> > > 93 389f5bcc744d Kevin Wolf:
> > >     iotests/046: Test that discard/write_zeroes wait for dependencies
> > 
> > since number 92 can cause an issue [0] that is much easier to run into
> > than the one it solves, but still similarly bad, I think it should only
> > be included together with Thomas' fix [1] on top. I know that one has
> > not been applied to master or reviewed by a maintainer yet, so if
> > including it goes against procedure, maybe it'd be better to leave 92
> > (and 93) out for now or delay the release?
> > 
> > Same for the other stable series. Thank you for the consideration!
> 
> Thank you very much for letting me know.  Yes, it isn't good to include
> "Fix corruption on discard" without the follow-up fix.  So it would be
> very nice to have the follow-up fix applied to the master branch today
> or tomorrow (this is Sat and Sun, maybe not the best timing), or I'll
> have to drop the above mentioned two changes from the stable series.
> Or indeed, releases should be delayed - in a hope the fix can be applied
> on Monday.
> 
> I'll wait for some reaction.  Kevin?

I was out yesterday and most of today, so I could only take a quick look
just now. The patch looks reasonable to me at first sight, I'll try to
have a closer look tomorrow.

Kevin



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen)
  2026-05-26 18:07     ` Kevin Wolf
@ 2026-05-26 18:09       ` Michael Tokarev
  2026-05-26 18:31         ` Kevin Wolf
  0 siblings, 1 reply; 42+ messages in thread
From: Michael Tokarev @ 2026-05-26 18:09 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: Fiona Ebner, qemu-stable, qemu-devel

On 26.05.2026 21:07, Kevin Wolf wrote:
> Am 23.05.2026 um 08:49 hat Michael Tokarev geschrieben:

>> I'll wait for some reaction.  Kevin?
> 
> I was out yesterday and most of today, so I could only take a quick look
> just now. The patch looks reasonable to me at first sight, I'll try to
> have a closer look tomorrow.

Thank you Kevin!

There's no rush anymore, I tagged stable releases yesterday already,
should be out once Mike creates and uploads the tarballs.

I removed the other patches from your pullreq which Fiona pointed
out previously, to be picked up once we have better time.

Maybe the next stable releases will be sooner than usual, due to
security fixes coming in.

Thanks,

/mjt


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen)
  2026-05-26 18:09       ` Michael Tokarev
@ 2026-05-26 18:31         ` Kevin Wolf
  0 siblings, 0 replies; 42+ messages in thread
From: Kevin Wolf @ 2026-05-26 18:31 UTC (permalink / raw)
  To: Michael Tokarev; +Cc: Fiona Ebner, qemu-stable, qemu-devel

Am 26.05.2026 um 20:09 hat Michael Tokarev geschrieben:
> On 26.05.2026 21:07, Kevin Wolf wrote:
> > Am 23.05.2026 um 08:49 hat Michael Tokarev geschrieben:
> 
> > > I'll wait for some reaction.  Kevin?
> > 
> > I was out yesterday and most of today, so I could only take a quick look
> > just now. The patch looks reasonable to me at first sight, I'll try to
> > have a closer look tomorrow.
> 
> Thank you Kevin!
> 
> There's no rush anymore, I tagged stable releases yesterday already,
> should be out once Mike creates and uploads the tarballs.
> 
> I removed the other patches from your pullreq which Fiona pointed
> out previously, to be picked up once we have better time.

Ok, perfect. I wasn't completely sure if I should actually recommend
removing the patches even if we have a follow-up patch because it
addresses a problem that has existed for a long time and people have
only reported it now. So it only makes sense that we're not trying to
rush something into stable that might end up making things worse.

> Maybe the next stable releases will be sooner than usual, due to
> security fixes coming in.

Hard to take this as good news, but it is what it is. :-)

Kevin



^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2026-05-26 18:32 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-22 21:33 [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 58/94] hw/uefi: check auth.hdr_length minimum size Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 60/94] hw/ufs: Validate MCQ SQ references before use Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 61/94] hw/ufs: Guard MCQ CQ accesses against missing queues Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 62/94] hw/ufs: Reject zero-depth MCQ queues Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 63/94] hw/ufs: Keep MCQ SQs alive while requests are outstanding Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 64/94] hw/ufs: Zero reserved bytes in REPORT LUNS response header Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 65/94] hw/display/cirrus_vga: Fix packed-24 color-expansion transparent pattern fills Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 66/94] hw/display/cirrus_vga: Fix packed-24 color-expansion transparent copies Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 67/94] hw/misc/aspeed_sbc: Add bounds checking for OTP write operations Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 68/94] aspeed/hace: Fix out-of-bounds read in has_padding() Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 69/94] aspeed/hace: Prevent total_req_len overflow Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 70/94] hw/i2c/microbit_i2c: Don't index off end of twi_read_sequence[] Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 71/94] ati-vga: fix ati_set_dirty address calculation Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 72/94] tests/qtest/iommu-smmuv3-test: Skip if no TCG GICv3 device present Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 73/94] meson.build: Add -fzero-init-padding-bits=all Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 74/94] hw/remote/machine.c: Mark x-remote machine as OK for AArch64 and AArch32 Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 75/94] tests/functional/qemu_test/asset.py: Don't use setxattr when it doesn't exist Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 76/94] target/arm/hvf: Fix WFI halting to stop idle vCPU spinning Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 77/94] hw/nvme: fix admin cq msix setup Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 78/94] linux-user: Fix AT_EXECFN in AUXV for symlinked programs Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 79/94] linux-user/sh4: Fix target_ucontext tuc_link field type Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 80/94] linux-user/sh4: Fix setup_sigtramp to match Linux kernel trampoline pattern Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 81/94] blkdebug: Add 'delay-ns' option Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 82/94] block: Add blk_co_start/end_request() and BDRV_REQ_NO_QUEUE Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 83/94] block: Add flags parameter to blk_*_pdiscard() Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 84/94] ide: Minimal fix for deadlock between TRIM and drain Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 85/94] ide: Clean up ide_trim_co_entry() to be idiomatic coroutine code Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 86/94] ide-test: Factor out wait_dma_completion() Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 87/94] ide-test: Test reset during TRIM Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 88/94] block: Create DEFAULT_BLOCK_CONF macro Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 89/94] block: Add more defaults to DEFAULT_BLOCK_CONF Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 90/94] commit: Drain nodes across all of bdrv_commit() Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 91/94] qemu-io: Add 'aio_discard' command Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 92/94] qcow2: Fix corruption on discard during write with COW Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 93/94] iotests/046: Test that discard/write_zeroes wait for dependencies Michael Tokarev
2026-05-22 21:33 ` [Stable-11.0.1 94/94] block/graph-lock: fix missed wakeup in bdrv_graph_co_rdunlock() Michael Tokarev
2026-05-22 23:10 ` [Stable-11.0.1 v2 00/94] Patch Round-up for stable 11.0.1, freeze on 2026-05-22 (frozen) Fiona Ebner
2026-05-23  6:49   ` Michael Tokarev
2026-05-26 18:07     ` Kevin Wolf
2026-05-26 18:09       ` Michael Tokarev
2026-05-26 18:31         ` Kevin Wolf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.