Files
qemu/hw/ide
Denis V. Lunev d9f78431d8 hw/ide/ahci: cancel in-flight buffered reads on command engine restart
ATAPI CD reads are issued through ide_buffered_readv()
(cd_read_sector() and ide_atapi_cmd_read_dma_cb() in hw/ide/atapi.c).
The PIO path discards the returned aiocb; the DMA path stores it in
s->bus->dma->aiocb.

A guest can stop and restart a port's command engine
(PxCMD.ST 1 -> 0 -> 1) while such a read is still in flight. Stopping
the engine unmaps the command list (ahci_unmap_clb_address()) and
restarting it re-maps the list and clears AHCIDevice.cur_cmd to NULL,
but nothing tears down the outstanding read. This path does not run
ide_reset(), so the drive's transfer state is preserved and the read
still completes. Its callbacks then dereference the stale or NULL
cur_cmd in the AHCI transfer helpers:

  PIO: cd_read_sector_cb() -> ide_atapi_cmd_reply_end() ->
       ide_transfer_start_norecurse() -> ahci_pio_transfer()

  DMA: ide_atapi_cmd_read_dma_cb() -> ahci_dma_rw_buf() ->
       ahci_populate_sglist()

Both crash with a NULL cur_cmd; the PIO variant has been seen in the
field.

Cancel the outstanding I/O when the command list is unmapped, reusing
ide_cancel_dma_sync() as the ATAPI DEVICE RESET command does. It runs
the completion callback with -ECANCELED (which tears down
s->bus->dma->aiocb for the DMA case) and orphans the buffered request,
so the eventual asynchronous completion is a no-op. Merely setting the
orphaned flag is not enough: it would leave s->bus->dma->aiocb pointing
at a freed aiocb that a later reset would cancel.

Fixes: 1d8c11d631 ("ide: add support for IDEBufferedRequest")
Signed-off-by: Denis V. Lunev <den@openvz.org>
Message-ID: <20260619112158.304782-2-den@openvz.org>
[PMD: Use ide_bus_active_if()]
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
2026-07-07 15:05:01 +02:00
..
2024-12-14 00:16:20 +01:00
2024-12-20 17:44:56 +01:00
2025-12-27 10:11:08 +01:00
2025-12-27 10:11:06 +01:00
2025-12-27 10:11:06 +01:00