iscsi-target: Fix iscsit_start_kthreads failure OOPs
[firefly-linux-kernel-4.4.55.git] / drivers / target / iscsi / iscsi_target.c
index a3fba366cebe457bc1a59a5006ff5290752d667a..202a42858f2537e7aa8f790f3969ba570ad93208 100644 (file)
@@ -29,7 +29,6 @@
 #include <scsi/scsi_tcq.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
-#include <target/target_core_configfs.h>
 
 #include <target/iscsi/iscsi_target_core.h>
 #include "iscsi_target_parameters.h"
@@ -716,7 +715,7 @@ static int iscsit_add_reject_from_cmd(
         */
        if (cmd->se_cmd.se_tfo != NULL) {
                pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
-               target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+               target_put_sess_cmd(&cmd->se_cmd);
        }
        return -1;
 }
@@ -1002,13 +1001,15 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length,
                conn->cid);
 
-       target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true);
+       target_get_sess_cmd(&cmd->se_cmd, true);
 
        cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd,
                                                     scsilun_to_int(&hdr->lun));
        if (cmd->sense_reason)
                goto attach_cmd;
 
+       /* only used for printks or comparing with ->ref_task_tag */
+       cmd->se_cmd.tag = (__force u32)cmd->init_task_tag;
        cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb);
        if (cmd->sense_reason) {
                if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) {
@@ -1068,7 +1069,7 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
                        return -1;
                else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
-                       target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+                       target_put_sess_cmd(&cmd->se_cmd);
                        return 0;
                }
        }
@@ -1084,7 +1085,7 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                if (!cmd->sense_reason)
                        return 0;
 
-               target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+               target_put_sess_cmd(&cmd->se_cmd);
                return 0;
        }
 
@@ -1115,7 +1116,6 @@ static int
 iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
                          bool dump_payload)
 {
-       struct iscsi_conn *conn = cmd->conn;
        int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
        /*
         * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
@@ -1142,7 +1142,7 @@ after_immediate_data:
 
                        rc = iscsit_dump_data_payload(cmd->conn,
                                                      cmd->first_burst_len, 1);
-                       target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+                       target_put_sess_cmd(&cmd->se_cmd);
                        return rc;
                } else if (cmd->unsolicited_data)
                        iscsit_set_unsoliticed_dataout(cmd);
@@ -1811,7 +1811,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                                      conn->sess->se_sess, 0, DMA_NONE,
                                      TCM_SIMPLE_TAG, cmd->sense_buffer + 2);
 
-               target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true);
+               target_get_sess_cmd(&cmd->se_cmd, true);
                sess_ref = true;
 
                switch (function) {
@@ -1953,7 +1953,7 @@ attach:
         */
        if (sess_ref) {
                pr_debug("Handle TMR, using sess_ref=true check\n");
-               target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+               target_put_sess_cmd(&cmd->se_cmd);
        }
 
        iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
@@ -2737,11 +2737,7 @@ static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
        cmd->iov_data_count = iov_count;
        cmd->tx_size = tx_size;
 
-       /* sendpage is preferred but can't insert markers */
-       if (!conn->conn_ops->IFMarker)
-               ret = iscsit_fe_sendpage_sg(cmd, conn);
-       else
-               ret = iscsit_send_tx_data(cmd, conn, 0);
+       ret = iscsit_fe_sendpage_sg(cmd, conn);
 
        iscsit_unmap_iovec(cmd);
 
@@ -4002,7 +3998,13 @@ get_immediate:
        }
 
 transport_err:
-       iscsit_take_action_for_connection_exit(conn);
+       /*
+        * Avoid the normal connection failure code-path if this connection
+        * is still within LOGIN mode, and iscsi_np process context is
+        * responsible for cleaning up the early connection failure.
+        */
+       if (conn->conn_state != TARG_CONN_STATE_IN_LOGIN)
+               iscsit_take_action_for_connection_exit(conn);
 out:
        return 0;
 }
@@ -4073,17 +4075,9 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
                        " opcode while ERL=0, closing iSCSI connection.\n");
                        return -1;
                }
-               if (!conn->conn_ops->OFMarker) {
-                       pr_err("Unable to recover from unknown"
-                       " opcode while OFMarker=No, closing iSCSI"
-                               " connection.\n");
-                       return -1;
-               }
-               if (iscsit_recover_from_unknown_opcode(conn) < 0) {
-                       pr_err("Unable to recover from unknown"
-                               " opcode, closing iSCSI connection.\n");
-                       return -1;
-               }
+               pr_err("Unable to recover from unknown opcode while OFMarker=No,"
+                      " closing iSCSI connection.\n");
+               ret = -1;
                break;
        }
 
@@ -4094,7 +4088,7 @@ reject:
 
 int iscsi_target_rx_thread(void *arg)
 {
-       int ret;
+       int ret, rc;
        u8 buffer[ISCSI_HDR_LEN], opcode;
        u32 checksum = 0, digest = 0;
        struct iscsi_conn *conn = arg;
@@ -4104,10 +4098,16 @@ int iscsi_target_rx_thread(void *arg)
         * connection recovery / failure event can be triggered externally.
         */
        allow_signal(SIGINT);
+       /*
+        * Wait for iscsi_post_login_handler() to complete before allowing
+        * incoming iscsi/tcp socket I/O, and/or failing the connection.
+        */
+       rc = wait_for_completion_interruptible(&conn->rx_login_comp);
+       if (rc < 0)
+               return 0;
 
        if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
                struct completion comp;
-               int rc;
 
                init_completion(&comp);
                rc = wait_for_completion_interruptible(&comp);
@@ -4777,6 +4777,7 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
        struct iscsi_session *sess;
        struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
        struct se_session *se_sess, *se_sess_tmp;
+       LIST_HEAD(free_list);
        int session_count = 0;
 
        spin_lock_bh(&se_tpg->session_lock);
@@ -4798,14 +4799,17 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
                }
                atomic_set(&sess->session_reinstatement, 1);
                spin_unlock(&sess->conn_lock);
-               spin_unlock_bh(&se_tpg->session_lock);
 
-               iscsit_free_session(sess);
-               spin_lock_bh(&se_tpg->session_lock);
+               list_move_tail(&se_sess->sess_list, &free_list);
+       }
+       spin_unlock_bh(&se_tpg->session_lock);
+
+       list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) {
+               sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
 
+               iscsit_free_session(sess);
                session_count++;
        }
-       spin_unlock_bh(&se_tpg->session_lock);
 
        pr_debug("Released %d iSCSI Session(s) from Target Portal"
                        " Group: %hu\n", session_count, tpg->tpgt);