libiscsi nops_in_flight stayed at 0 on a dead TCP session, so QEMU never
noticed the target had vanished when command timeout was disabled.

See: https://gitlab.com/qemu-project/qemu/-/work_items/3067
Signed-off-by: Konstantin Nigmatullin <[email protected]>
---
 block/iscsi.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/block/iscsi.c b/block/iscsi.c
index 7d6bf185ea..bf74b4cb65 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -103,6 +103,8 @@ typedef struct IscsiLun {
     bool dpofua;
     bool has_write_same;
     bool request_timed_out;
+    /* Consecutive NOP-Outs without a successful NOP-In reply. */
+    int nop_failures;
 } IscsiLun;
 
 typedef struct IscsiTask {
@@ -1398,17 +1400,37 @@ static char *get_initiator_name(QemuOpts *opts)
     return iscsi_name;
 }
 
+static void iscsi_nop_cb(struct iscsi_context *iscsi, int status,
+                         void *command_data, void *opaque)
+{
+    IscsiLun *iscsilun = opaque;
+
+    if (status == SCSI_STATUS_GOOD) {
+        iscsilun->nop_failures = 0;
+    }
+}
+
 static void iscsi_nop_timed_event(void *opaque)
 {
     IscsiLun *iscsilun = opaque;
 
     QEMU_LOCK_GUARD(&iscsilun->mutex);
-    if (iscsi_get_nops_in_flight(iscsilun->iscsi) >= MAX_NOP_FAILURES) {
+    /*
+     * Prefer libiscsi's counter when it works; also track locally because
+     * some libiscsi builds leave nops_in_flight at 0 across a dead TCP
+     * session, which disabled disconnect detection entirely.
+     */
+    if (iscsilun->nop_failures >= MAX_NOP_FAILURES ||
+        iscsi_get_nops_in_flight(iscsilun->iscsi) >= MAX_NOP_FAILURES) {
         error_report("iSCSI: NOP timeout. Reconnecting...");
         iscsilun->request_timed_out = true;
-    } else if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) 
{
+        iscsilun->nop_failures = 0;
+    } else if (iscsi_nop_out_async(iscsilun->iscsi, iscsi_nop_cb, NULL, 0,
+                                   iscsilun) != 0) {
         error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
         return;
+    } else {
+        iscsilun->nop_failures++;
     }
 
     timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 
NOP_INTERVAL);
-- 
2.53.0


Reply via email to