]> git.baikalelectronics.ru Git - kernel.git/commitdiff
scsi: iscsi: Remove unneeded task state check
authorMike Christie <michael.christie@oracle.com>
Thu, 16 Jun 2022 22:45:54 +0000 (17:45 -0500)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 22 Jun 2022 01:19:23 +0000 (21:19 -0400)
Commit d0757df95b24 ("scsi: libiscsi: Drop taskqueuelock") added an extra
task->state because for commit 4a81c36e3a80 ("scsi: libiscsi: add lock
around task lists to fix list corruption regression") we didn't know why we
ended up with cmds on the list and thought it might have been a bad target
sending a response while we were still sending the cmd. We were never able
to get a target to send us a response early, because it turns out the bug
was just a race in libiscsi/libiscsi_tcp where:

 1. iscsi_tcp_r2t_rsp() queues a r2t to tcp_task->r2tqueue.

 2. iscsi_tcp_task_xmit() runs iscsi_tcp_get_curr_r2t() and sees we have a
    r2t. It dequeues it and iscsi_tcp_task_xmit() starts to process it.

 3. iscsi_tcp_r2t_rsp() runs iscsi_requeue_task() and puts the task on the
    requeue list.

 4. iscsi_tcp_task_xmit() sends the data for r2t. This is the final chunk
    of data, so the cmd is done.

 5. target sends the response.

 6. On a different CPU from #3, iscsi_complete_task() processes the
    response.  Since there was no common lock for the list, the lists/tasks
    pointers are not fully in sync, so could end up with list corruption.

Since it was just a race on our side, remove the extra check and fix up the
comments.

Link: https://lore.kernel.org/r/20220616224557.115234-7-michael.christie@oracle.com
Reviewed-by: Wu Bo <wubo40@huawei.com>
Reviewed-by: Lee Duncan <lduncan@suse.com>
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/libiscsi.c

index 20156fb33646825a89f27201ae163cb46782402a..fce9f9e5b00b62bfa68f21983e9079b27a2d59a8 100644 (file)
@@ -567,16 +567,19 @@ static bool cleanup_queued_task(struct iscsi_task *task)
        struct iscsi_conn *conn = task->conn;
        bool early_complete = false;
 
-       /* Bad target might have completed task while it was still running */
+       /*
+        * We might have raced where we handled a R2T early and got a response
+        * but have not yet taken the task off the requeue list, then a TMF or
+        * recovery happened and so we can still see it here.
+        */
        if (task->state == ISCSI_TASK_COMPLETED)
                early_complete = true;
 
        if (!list_empty(&task->running)) {
                list_del_init(&task->running);
                /*
-                * If it's on a list but still running, this could be from
-                * a bad target sending a rsp early, cleanup from a TMF, or
-                * session recovery.
+                * If it's on a list but still running this could be cleanup
+                * from a TMF or session recovery.
                 */
                if (task->state == ISCSI_TASK_RUNNING ||
                    task->state == ISCSI_TASK_COMPLETED)
@@ -1485,7 +1488,7 @@ static int iscsi_xmit_task(struct iscsi_conn *conn, struct iscsi_task *task,
        }
        /* regular RX path uses back_lock */
        spin_lock(&conn->session->back_lock);
-       if (rc && task->state == ISCSI_TASK_RUNNING) {
+       if (rc) {
                /*
                 * get an extra ref that is released next time we access it
                 * as conn->task above.