From: "Philippe Mathieu-Daudé" <philmd@oss.qualcomm.com>
To: qemu-devel@nongnu.org
Subject: [PULL v2 05/36] tests/qtest/ahci: test ATAPI read completing after engine restart
Date: Tue, 7 Jul 2026 17:13:48 +0200 [thread overview]
Message-ID: <20260707151351.57769-2-philmd@oss.qualcomm.com> (raw)
In-Reply-To: <20260707151351.57769-1-philmd@oss.qualcomm.com>
From: "Denis V. Lunev" <den@openvz.org>
Add a regression test for the crash that occurs when a buffered ATAPI
read completes after the command engine has been restarted. Issue an
ATAPI READ_10 against a blkdebug-backed CD, suspend the backend read so
it stays in flight, stop and restart the port's command engine (which
re-maps the command list and clears cur_cmd), then release the read.
The PIO and DMA reply paths fault in different AHCI helpers
(ahci_pio_transfer() vs ahci_dma_rw_buf()), so cover both. The DMA
variant is the reliable guard: on engine restart check_cmd() can re-arm
cur_cmd before the old read completes, so the PIO variant does not fault
in every build.
The test only asserts that qemu survives a subsequent register access;
if the blkdebug breakpoint ever failed to park the read it would pass
without exercising the bug, as with the existing break/resume tests.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Message-ID: <20260619112158.304782-3-den@openvz.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
tests/qtest/ahci-test.c | 67 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c
index 5c32ff20029..44799eea153 100644
--- a/tests/qtest/ahci-test.c
+++ b/tests/qtest/ahci-test.c
@@ -1625,6 +1625,69 @@ static void test_cdrom_pio_multi(void)
ahci_test_cdrom_read10(3, false);
}
+/*
+ * Regression test: a buffered ATAPI read completing after a command
+ * engine restart must not dereference the cleared cur_cmd. Cover both
+ * PIO and DMA; the DMA variant is the reliable guard.
+ */
+static void test_atapi_engine_restart_in_flight(bool dma)
+{
+ AHCIQState *ahci;
+ AHCICommand *cmd;
+ unsigned char *tx;
+ char *iso;
+ int fd;
+ uint8_t port;
+ uint64_t buffer;
+ uint64_t iso_size = (uint64_t)ATAPI_SECTOR_SIZE * 2;
+
+ fd = prepare_iso(iso_size, &tx, &iso);
+
+ ahci = ahci_boot_and_enable("-drive if=none,id=drive0,"
+ "file=blkdebug::%s,format=raw,readonly=on "
+ "-M q35 "
+ "-device ide-cd,drive=drive0 ", iso);
+ port = ahci_port_select(ahci);
+
+ buffer = ahci_alloc(ahci, ATAPI_SECTOR_SIZE);
+ qtest_memset(ahci->parent->qts, buffer, 0x00, ATAPI_SECTOR_SIZE);
+
+ /* Suspend the next backend read so the ATAPI read stays in flight. */
+ g_free(qtest_hmp(ahci->parent->qts,
+ "qemu-io drive0 \"break read_aio rd\""));
+
+ cmd = ahci_atapi_command_create(CMD_ATAPI_READ_10, ATAPI_SECTOR_SIZE,
+ dma);
+ ahci_command_adjust(cmd, 0, buffer, ATAPI_SECTOR_SIZE, 0);
+ ahci_command_commit(ahci, cmd, port);
+ ahci_command_issue_async(ahci, cmd);
+
+ /* Stop and restart the command engine to re-map the command list. */
+ ahci_px_clr(ahci, port, AHCI_PX_CMD, AHCI_PX_CMD_ST);
+ ahci_px_set(ahci, port, AHCI_PX_CMD, AHCI_PX_CMD_ST);
+
+ g_free(qtest_hmp(ahci->parent->qts, "qemu-io drive0 \"resume rd\""));
+
+ /* Round-trip through the device to confirm qemu is still alive. */
+ ahci_px_rreg(ahci, port, AHCI_PX_TFD);
+
+ ahci_command_free(cmd);
+ ahci_free(ahci, buffer);
+ g_free(tx);
+ ahci_shutdown(ahci);
+ remove_iso(fd, iso);
+}
+
+static void test_atapi_engine_restart_pio(void)
+{
+ test_atapi_engine_restart_in_flight(false);
+}
+
+static void test_atapi_engine_restart_dma(void)
+{
+ test_atapi_engine_restart_in_flight(true);
+}
+
/* Regression test: Test that a READ_CD command with a BCL of 0 but a size of 0
* completes as a NOP instead of erroring out. */
static void test_atapi_bcl(void)
@@ -2042,6 +2105,10 @@ int main(int argc, char **argv)
qtest_add_func("/ahci/cdrom/pio/bcl", test_atapi_bcl);
qtest_add_func("/ahci/cdrom/eject", test_atapi_tray);
+ qtest_add_func("/ahci/cdrom/engine_restart/pio",
+ test_atapi_engine_restart_pio);
+ qtest_add_func("/ahci/cdrom/engine_restart/dma",
+ test_atapi_engine_restart_dma);
ret = g_test_run();
--
2.53.0
next prev parent reply other threads:[~2026-07-07 15:14 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-07 15:13 [PULL v2 00/36] Misc HW patches for 2026-07-07 Philippe Mathieu-Daudé
2026-07-07 15:13 ` Philippe Mathieu-Daudé [this message]
2026-07-07 15:13 ` [PULL v2 29/36] hw/arm/msf2-som: Fix spansion-cr2nv value for S25FL128S Philippe Mathieu-Daudé
2026-07-07 15:13 ` [PULL v2 30/36] hw/block: m25p80: Fix dummy byte handling for Spansion flash Philippe Mathieu-Daudé
2026-07-07 15:13 ` [PULL v2 36/36] MAINTAINERS: update Chao Liu's email address Philippe Mathieu-Daudé
2026-07-08 5:54 ` [PULL v2 00/36] Misc HW patches for 2026-07-07 Stefan Hajnoczi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260707151351.57769-2-philmd@oss.qualcomm.com \
--to=philmd@oss.qualcomm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.