iscsi-target: Fix iscsit_sequence_cmd reject handling for iser
authorNicholas Bellinger <nab@linux-iscsi.org>
Wed, 3 Jul 2013 10:58:58 +0000 (03:58 -0700)
committerNicholas Bellinger <nab@linux-iscsi.org>
Sun, 7 Jul 2013 04:59:54 +0000 (21:59 -0700)
This patch moves ISCSI_OP_REJECT failures into iscsit_sequence_cmd()
in order to avoid external iscsit_reject_cmd() reject usage for all
PDU types.

It also updates PDU specific handlers for traditional iscsi-target
code to not reset the session after posting a ISCSI_OP_REJECT during
setup.

(v2: Fix CMDSN_LOWER_THAN_EXP for ISCSI_OP_SCSI to call
     target_put_sess_cmd() after iscsit_sequence_cmd() failure)

Cc: Or Gerlitz <ogerlitz@mellanox.com>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Cc: stable@vger.kernel.org # 3.10+
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/infiniband/ulp/isert/ib_isert.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
include/target/iscsi/iscsi_transport.h

index 134ff58c6b1730ea7a396856c7d000798df7a884..7e219a46e7ca28e4dad2532bf4849495a9424804 100644 (file)
@@ -934,7 +934,7 @@ isert_handle_scsi_cmd(struct isert_conn *isert_conn,
        }
 
 sequence_cmd:
-       rc = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+       rc = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
 
        if (!rc && dump_payload == false && unsol_data)
                iscsit_set_unsoliticed_dataout(cmd);
index 2a25bd3b065c333dcf1303f05eb167a4a4d601e0..4319dad7d9195f6c210ebac4ab7f380386c4d3fe 100644 (file)
@@ -1052,11 +1052,11 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
         * be acknowledged. (See below)
         */
        if (!cmd->immediate_data) {
-               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
-               if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
-                       if (!cmd->sense_reason)
-                               return 0;
-
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
+                                       (unsigned char *)hdr, hdr->cmdsn);
+               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);
                        return 0;
                }
@@ -1083,6 +1083,9 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
         * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.
         */
        if (cmd->sense_reason) {
+               if (cmd->reject_reason)
+                       return 0;
+
                target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
                return 1;
        }
@@ -1091,10 +1094,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
         * the backend memory allocation.
         */
        cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd);
-       if (cmd->sense_reason) {
-               target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+       if (cmd->sense_reason)
                return 1;
-       }
 
        return 0;
 }
@@ -1104,6 +1105,7 @@ 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.
@@ -1120,12 +1122,22 @@ after_immediate_data:
                 * DataCRC, check against ExpCmdSN/MaxCmdSN if
                 * Immediate Bit is not set.
                 */
-               cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, hdr->cmdsn);
+               cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd,
+                                       (unsigned char *)hdr, hdr->cmdsn);
+               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);
+                       return 0;
+               }
 
                if (cmd->sense_reason) {
-                       if (iscsit_dump_data_payload(cmd->conn,
-                                       cmd->first_burst_len, 1) < 0)
-                               return -1;
+                       int rc;
+
+                       rc = iscsit_dump_data_payload(cmd->conn,
+                                                     cmd->first_burst_len, 1);
+                       target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+                       return rc;
                } else if (cmd->unsolicited_data)
                        iscsit_set_unsoliticed_dataout(cmd);
 
@@ -1159,7 +1171,7 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
 
        rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
        if (rc < 0)
-               return rc;
+               return 0;
        /*
         * Allocation iovecs needed for struct socket operations for
         * traditional iSCSI block I/O.
@@ -1494,7 +1506,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
 
        rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
        if (rc < 0)
-               return rc;
+               return 0;
        else if (!cmd)
                return 0;
 
@@ -1579,10 +1591,10 @@ int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                        return 0;
                }
 
-               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
+                               (unsigned char *)hdr, hdr->cmdsn);
                 if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
                        return 0;
-
                if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
                        return -1;
 
@@ -1623,7 +1635,7 @@ static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
 
        ret = iscsit_setup_nop_out(conn, cmd, hdr);
        if (ret < 0)
-               return ret;
+               return 0;
        /*
         * Handle NOP-OUT payload for traditional iSCSI sockets
         */
@@ -1893,7 +1905,7 @@ attach:
        spin_unlock_bh(&conn->cmd_lock);
 
        if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
-               int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
                if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
                        out_of_order_cmdsn = 1;
                else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
@@ -1996,7 +2008,8 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
        iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
 
        if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
-               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
+                               (unsigned char *)hdr, hdr->cmdsn);
                if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
                        return -1;
 
@@ -2022,7 +2035,7 @@ iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
 
        rc = iscsit_setup_text_cmd(conn, cmd, hdr);
        if (rc < 0)
-               return rc;
+               return 0;
 
        rx_size = payload_length;
        if (payload_length) {
@@ -2284,7 +2297,7 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                if (ret < 0)
                        return ret;
        } else {
-               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+               cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
                if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
                        logout_remove = 0;
                else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
index d00f1326f0c88bc431d6489c86ca723ca46916a1..586c268679a450aa9b382d9d42b23ca5dfe0cf35 100644 (file)
@@ -1088,7 +1088,7 @@ int iscsit_handle_ooo_cmdsn(
 
        ooo_cmdsn = iscsit_allocate_ooo_cmdsn();
        if (!ooo_cmdsn)
-               return CMDSN_ERROR_CANNOT_RECOVER;
+               return -ENOMEM;
 
        ooo_cmdsn->cmd                  = cmd;
        ooo_cmdsn->batch_count          = (batch) ?
@@ -1099,10 +1099,10 @@ int iscsit_handle_ooo_cmdsn(
 
        if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) {
                kmem_cache_free(lio_ooo_cache, ooo_cmdsn);
-               return CMDSN_ERROR_CANNOT_RECOVER;
+               return -ENOMEM;
        }
 
-       return CMDSN_HIGHER_THAN_EXP;
+       return 0;
 }
 
 static int iscsit_set_dataout_timeout_values(
index 96ce6f2ec428492b435b70fbf0ad6d655bbe2a02..1df06d5e4e01ee29353801a671b43d62bf934fbf 100644 (file)
@@ -283,13 +283,12 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm
  * Commands may be received out of order if MC/S is in use.
  * Ensure they are executed in CmdSN order.
  */
-int iscsit_sequence_cmd(
-       struct iscsi_conn *conn,
-       struct iscsi_cmd *cmd,
-       __be32 cmdsn)
+int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                       unsigned char *buf, __be32 cmdsn)
 {
-       int ret;
-       int cmdsn_ret;
+       int ret, cmdsn_ret;
+       bool reject = false;
+       u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES;
 
        mutex_lock(&conn->sess->cmdsn_mutex);
 
@@ -299,9 +298,19 @@ int iscsit_sequence_cmd(
                ret = iscsit_execute_cmd(cmd, 0);
                if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list))
                        iscsit_execute_ooo_cmdsns(conn->sess);
+               else if (ret < 0) {
+                       reject = true;
+                       ret = CMDSN_ERROR_CANNOT_RECOVER;
+               }
                break;
        case CMDSN_HIGHER_THAN_EXP:
                ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn));
+               if (ret < 0) {
+                       reject = true;
+                       ret = CMDSN_ERROR_CANNOT_RECOVER;
+                       break;
+               }
+               ret = CMDSN_HIGHER_THAN_EXP;
                break;
        case CMDSN_LOWER_THAN_EXP:
                cmd->i_state = ISTATE_REMOVE;
@@ -309,11 +318,16 @@ int iscsit_sequence_cmd(
                ret = cmdsn_ret;
                break;
        default:
+               reason = ISCSI_REASON_PROTOCOL_ERROR;
+               reject = true;
                ret = cmdsn_ret;
                break;
        }
        mutex_unlock(&conn->sess->cmdsn_mutex);
 
+       if (reject)
+               iscsit_reject_cmd(cmd, reason, buf);
+
        return ret;
 }
 EXPORT_SYMBOL(iscsit_sequence_cmd);
index a4422659d04944f58c85670bfd08c646c1bcf5ff..e4fc34a02f57b0d7ed88354a315efa87f41ed500 100644 (file)
@@ -13,7 +13,8 @@ extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
 extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
 extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
 extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
-int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, __be32 cmdsn);
+extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                              unsigned char * ,__be32 cmdsn);
 extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);
 extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
 extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
index 19a43ad977c26da139d089bfb85bbf1c7be4792a..ce4070d8f156cb70fe040625eaf39c8a61b75cd1 100644 (file)
@@ -86,4 +86,5 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
  * From iscsi_target_util.c
  */
 extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
-extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *, __be32);
+extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+                              unsigned char *, __be32);