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: 1d8c11d63154 ("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>