scsi: iscsi: Prefer xmit of DataOut over new commands
authorDmitry Bogdanov <d.bogdanov@yadro.com>
Tue, 7 Jun 2022 13:19:53 +0000 (16:19 +0300)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 17 Jun 2022 01:53:39 +0000 (21:53 -0400)
iscsi_data_xmit() (TX worker) is iterating over the queue of new SCSI
commands concurrently with the queue being replenished. Only after the
queue is emptied will we start sending pending DataOut PDUs. That leads to
DataOut timeout on the target side and to connection reinstatement.

Give priority to pending DataOut commands over new commands.

Link: https://lore.kernel.org/r/20220607131953.11584-1-d.bogdanov@yadro.com
Reviewed-by: Konstantin Shelekhin <k.shelekhin@yadro.com>
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/libiscsi.c

index 797abf4..8d78559 100644 (file)
@@ -1567,6 +1567,28 @@ check_mgmt:
                        goto done;
        }
 
+check_requeue:
+       while (!list_empty(&conn->requeue)) {
+               /*
+                * we always do fastlogout - conn stop code will clean up.
+                */
+               if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
+                       break;
+
+               task = list_entry(conn->requeue.next, struct iscsi_task,
+                                 running);
+
+               if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT))
+                       break;
+
+               list_del_init(&task->running);
+               rc = iscsi_xmit_task(conn, task, true);
+               if (rc)
+                       goto done;
+               if (!list_empty(&conn->mgmtqueue))
+                       goto check_mgmt;
+       }
+
        /* process pending command queue */
        while (!list_empty(&conn->cmdqueue)) {
                task = list_entry(conn->cmdqueue.next, struct iscsi_task,
@@ -1594,28 +1616,10 @@ check_mgmt:
                 */
                if (!list_empty(&conn->mgmtqueue))
                        goto check_mgmt;
+               if (!list_empty(&conn->requeue))
+                       goto check_requeue;
        }
 
-       while (!list_empty(&conn->requeue)) {
-               /*
-                * we always do fastlogout - conn stop code will clean up.
-                */
-               if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
-                       break;
-
-               task = list_entry(conn->requeue.next, struct iscsi_task,
-                                 running);
-
-               if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT))
-                       break;
-
-               list_del_init(&task->running);
-               rc = iscsi_xmit_task(conn, task, true);
-               if (rc)
-                       goto done;
-               if (!list_empty(&conn->mgmtqueue))
-                       goto check_mgmt;
-       }
        spin_unlock_bh(&conn->session->frwd_lock);
        return -ENODATA;