From: Nicholas Bellinger <n...@linux-iscsi.org>

This patch fixes a regression introduced with the following commit
in v4.0-rc1 code:

    commit 88dcd2dab5c23b1c9cfc396246d8f476c872f0ca
    Author: Nicholas Bellinger <n...@linux-iscsi.org>
    Date:   Thu Feb 26 22:19:15 2015 -0800

        iscsi-target: Convert iscsi_thread_set usage to kthread.h

where iscsit_start_kthreads() failure would result in a NULL pointer
dereference OOPs.

To address this bug, it adds a iscsit_kthread_err() helper to cleanup
both zero_tsih and !zero_tsih cases, and a iscsi_target_tx_thread()
special case to avoid iscsit_take_action_for_connection_exit() during
the late iscsit_start_kthreads() -> kthread_run() failure case for
iscsi_target_rx_thread().

Cc: Sagi Grimberg <sa...@mellanox.com>
Cc: <sta...@vger.kernel.org> # v3.10+
Signed-off-by: Nicholas Bellinger <n...@linux-iscsi.org>
---
 drivers/target/iscsi/iscsi_target.c       |  3 ++-
 drivers/target/iscsi/iscsi_target_login.c | 39 +++++++++++++++++++++++++++----
 2 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/drivers/target/iscsi/iscsi_target.c 
b/drivers/target/iscsi/iscsi_target.c
index 4e68b62..66655b7 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -3998,7 +3998,8 @@ get_immediate:
        }
 
 transport_err:
-       iscsit_take_action_for_connection_exit(conn);
+       if (conn->rx_thread_active)
+               iscsit_take_action_for_connection_exit(conn);
 out:
        return 0;
 }
diff --git a/drivers/target/iscsi/iscsi_target_login.c 
b/drivers/target/iscsi/iscsi_target_login.c
index 3d0fe4f..76dedb6 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -679,6 +679,7 @@ static int iscsit_start_kthreads(struct iscsi_conn *conn)
 
        return 0;
 out_tx:
+       send_sig(SIGINT, conn->tx_thread, 1);
        kthread_stop(conn->tx_thread);
        conn->tx_thread_active = false;
 out_bitmap:
@@ -689,6 +690,23 @@ out_bitmap:
        return ret;
 }
 
+static void iscsit_kthread_err(struct iscsi_session *sess,
+                              struct iscsi_conn *conn, bool new_sess)
+{
+       spin_lock_bh(&sess->conn_lock);
+       list_del(&conn->conn_list);
+       if (atomic_dec_and_test(&sess->nconn))
+               sess->session_state = TARG_SESS_STATE_FAILED;
+       spin_unlock_bh(&sess->conn_lock);
+
+       if (!new_sess)
+               return;
+
+       transport_deregister_session_configfs(sess->se_sess);
+       transport_deregister_session(sess->se_sess);
+       sess->se_sess = NULL;
+}
+
 int iscsi_post_login_handler(
        struct iscsi_np *np,
        struct iscsi_conn *conn,
@@ -740,8 +758,10 @@ int iscsi_post_login_handler(
                spin_unlock_bh(&sess->conn_lock);
 
                rc = iscsit_start_kthreads(conn);
-               if (rc)
-                       return rc;
+               if (rc) {
+                       iscsit_kthread_err(sess, conn, false);
+                       goto out_old_sess;
+               }
 
                iscsi_post_login_start_timers(conn);
                /*
@@ -751,7 +771,7 @@ int iscsi_post_login_handler(
                iscsit_thread_get_cpumask(conn);
                conn->conn_rx_reset_cpumask = 1;
                conn->conn_tx_reset_cpumask = 1;
-
+out_old_sess:
                iscsit_dec_conn_usage_count(conn);
                if (stop_timer) {
                        spin_lock_bh(&se_tpg->session_lock);
@@ -759,7 +779,7 @@ int iscsi_post_login_handler(
                        spin_unlock_bh(&se_tpg->session_lock);
                }
                iscsit_dec_session_usage_count(sess);
-               return 0;
+               return rc;
        }
 
        iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1);
@@ -801,8 +821,17 @@ int iscsi_post_login_handler(
        spin_unlock_bh(&se_tpg->session_lock);
 
        rc = iscsit_start_kthreads(conn);
-       if (rc)
+       if (rc) {
+               spin_lock_bh(&se_tpg->session_lock);
+               if (tpg->tpg_tiqn)
+                       tpg->tpg_tiqn->tiqn_nsessions--;
+               tpg->nsessions--;
+               spin_unlock_bh(&se_tpg->session_lock);
+
+               iscsit_kthread_err(sess, conn, true);
+               iscsit_dec_conn_usage_count(conn);
                return rc;
+       }
 
        iscsi_post_login_start_timers(conn);
        /*
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to