When an iSCSI target disappears (for example tgtd is killed), QEMU can
leave guest I/O stuck and then fail to exit on SIGINT because
virtio_scsi_dataplane_stop blocks forever in blk_drain_all().
This is a stack of problems in block/iscsi.c, not only the documented
default command timeout of 0:
1. NOP dead-session detection never fired in practice because
iscsi_get_nops_in_flight() stayed at 0 on a dead TCP session.
2. SCSI_STATUS_TIMEOUT was retried like BUSY (up to seven full
timeouts), so drain stayed busy for minutes even with -iscsi
timeout=N.
3. In-flight coroutines were not cancelled locally, so with timeout=0
waiters never woke.
4. After one failure, queued I/O restarted another long wait, so drain
never stayed idle (permanent hang).
This series addresses those without changing the default timeout value.
Verified with the GitLab #3067 recipe (default timeout=0). After killing
tgtd and unmounting, the guest correctly sees I/O errors, and Ctrl-C
makes QEMU exit cleanly instead of hanging in blk_drain_all:
(initramfs) umount /mnt
qemu-system-x86_64: terminating on signal 2
qemu-system-x86_64: iSCSI: NOP timeout. Reconnecting...
qemu-system-x86_64: iSCSI SYNCHRONIZECACHE10 failed: SENSE KEY:UNIT_ATTENTION(6) ASCQ:BUS_RESET(0x2900)
Residual host messages such as NOP timeout / SYNCHRONIZECACHE10
UNIT_ATTENTION(BUS_RESET) are expected while in-flight flush fails on a
dead session during reconnect; they are cosmetic and not a correctness
issue for this series.
Buglink: https://gitlab.com/qemu-project/qemu/-/issues/3067
Konstantin Nigmatullin (5):
iscsi: detect dead iSCSI sessions via local NOP failure counting
iscsi: stop retrying timed-out iSCSI commands
iscsi: cancel in-flight iSCSI tasks when the session dies
iscsi: fail new iSCSI I/O while the transport is known down
iscsi: avoid null iSCSI error strings after cancel or timeout
block/iscsi.c | 124 +++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 113 insertions(+), 11 deletions(-)
--
2.53.0