Commit 561bf158 authored by Nicholas Bellinger's avatar Nicholas Bellinger

iscsi-target: Fix iscsit_sequence_cmd reject handling for iser

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: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent ba159914
...@@ -934,7 +934,7 @@ isert_handle_scsi_cmd(struct isert_conn *isert_conn, ...@@ -934,7 +934,7 @@ isert_handle_scsi_cmd(struct isert_conn *isert_conn,
} }
sequence_cmd: 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) if (!rc && dump_payload == false && unsol_data)
iscsit_set_unsoliticed_dataout(cmd); iscsit_set_unsoliticed_dataout(cmd);
......
...@@ -1052,11 +1052,11 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -1052,11 +1052,11 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
* be acknowledged. (See below) * be acknowledged. (See below)
*/ */
if (!cmd->immediate_data) { if (!cmd->immediate_data) {
cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); cmdsn_ret = iscsit_sequence_cmd(conn, cmd,
if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { (unsigned char *)hdr, hdr->cmdsn);
if (!cmd->sense_reason) if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return 0; 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(conn->sess->se_sess, &cmd->se_cmd);
return 0; return 0;
} }
...@@ -1083,6 +1083,9 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -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. * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.
*/ */
if (cmd->sense_reason) { if (cmd->sense_reason) {
if (cmd->reject_reason)
return 0;
target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
return 1; return 1;
} }
...@@ -1091,10 +1094,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -1091,10 +1094,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
* the backend memory allocation. * the backend memory allocation.
*/ */
cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd); cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd);
if (cmd->sense_reason) { if (cmd->sense_reason)
target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
return 1; return 1;
}
return 0; return 0;
} }
...@@ -1104,6 +1105,7 @@ static int ...@@ -1104,6 +1105,7 @@ static int
iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
bool dump_payload) bool dump_payload)
{ {
struct iscsi_conn *conn = cmd->conn;
int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
/* /*
* Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
...@@ -1120,12 +1122,22 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, ...@@ -1120,12 +1122,22 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
* DataCRC, check against ExpCmdSN/MaxCmdSN if * DataCRC, check against ExpCmdSN/MaxCmdSN if
* Immediate Bit is not set. * 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 (cmd->sense_reason) {
if (iscsit_dump_data_payload(cmd->conn, int rc;
cmd->first_burst_len, 1) < 0)
return -1; 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) } else if (cmd->unsolicited_data)
iscsit_set_unsoliticed_dataout(cmd); iscsit_set_unsoliticed_dataout(cmd);
...@@ -1159,7 +1171,7 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *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); rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
if (rc < 0) if (rc < 0)
return rc; return 0;
/* /*
* Allocation iovecs needed for struct socket operations for * Allocation iovecs needed for struct socket operations for
* traditional iSCSI block I/O. * traditional iSCSI block I/O.
...@@ -1494,7 +1506,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) ...@@ -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); rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
if (rc < 0) if (rc < 0)
return rc; return 0;
else if (!cmd) else if (!cmd)
return 0; return 0;
...@@ -1579,10 +1591,10 @@ int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -1579,10 +1591,10 @@ int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
return 0; 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) if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
return 0; return 0;
if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return -1; return -1;
...@@ -1623,7 +1635,7 @@ static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -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); ret = iscsit_setup_nop_out(conn, cmd, hdr);
if (ret < 0) if (ret < 0)
return ret; return 0;
/* /*
* Handle NOP-OUT payload for traditional iSCSI sockets * Handle NOP-OUT payload for traditional iSCSI sockets
*/ */
...@@ -1893,7 +1905,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -1893,7 +1905,7 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
spin_unlock_bh(&conn->cmd_lock); spin_unlock_bh(&conn->cmd_lock);
if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { 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) if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)
out_of_order_cmdsn = 1; out_of_order_cmdsn = 1;
else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
...@@ -1996,7 +2008,8 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -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)); iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { 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) if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return -1; return -1;
...@@ -2022,7 +2035,7 @@ iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -2022,7 +2035,7 @@ iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
rc = iscsit_setup_text_cmd(conn, cmd, hdr); rc = iscsit_setup_text_cmd(conn, cmd, hdr);
if (rc < 0) if (rc < 0)
return rc; return 0;
rx_size = payload_length; rx_size = payload_length;
if (payload_length) { if (payload_length) {
...@@ -2284,7 +2297,7 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ...@@ -2284,7 +2297,7 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
if (ret < 0) if (ret < 0)
return ret; return ret;
} else { } 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) if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
logout_remove = 0; logout_remove = 0;
else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
......
...@@ -1088,7 +1088,7 @@ int iscsit_handle_ooo_cmdsn( ...@@ -1088,7 +1088,7 @@ int iscsit_handle_ooo_cmdsn(
ooo_cmdsn = iscsit_allocate_ooo_cmdsn(); ooo_cmdsn = iscsit_allocate_ooo_cmdsn();
if (!ooo_cmdsn) if (!ooo_cmdsn)
return CMDSN_ERROR_CANNOT_RECOVER; return -ENOMEM;
ooo_cmdsn->cmd = cmd; ooo_cmdsn->cmd = cmd;
ooo_cmdsn->batch_count = (batch) ? ooo_cmdsn->batch_count = (batch) ?
...@@ -1099,10 +1099,10 @@ int iscsit_handle_ooo_cmdsn( ...@@ -1099,10 +1099,10 @@ int iscsit_handle_ooo_cmdsn(
if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) { if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) {
kmem_cache_free(lio_ooo_cache, ooo_cmdsn); 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( static int iscsit_set_dataout_timeout_values(
......
...@@ -283,13 +283,12 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm ...@@ -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. * Commands may be received out of order if MC/S is in use.
* Ensure they are executed in CmdSN order. * Ensure they are executed in CmdSN order.
*/ */
int iscsit_sequence_cmd( int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
struct iscsi_conn *conn, unsigned char *buf, __be32 cmdsn)
struct iscsi_cmd *cmd,
__be32 cmdsn)
{ {
int ret; int ret, cmdsn_ret;
int cmdsn_ret; bool reject = false;
u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES;
mutex_lock(&conn->sess->cmdsn_mutex); mutex_lock(&conn->sess->cmdsn_mutex);
...@@ -299,9 +298,19 @@ int iscsit_sequence_cmd( ...@@ -299,9 +298,19 @@ int iscsit_sequence_cmd(
ret = iscsit_execute_cmd(cmd, 0); ret = iscsit_execute_cmd(cmd, 0);
if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list)) if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list))
iscsit_execute_ooo_cmdsns(conn->sess); iscsit_execute_ooo_cmdsns(conn->sess);
else if (ret < 0) {
reject = true;
ret = CMDSN_ERROR_CANNOT_RECOVER;
}
break; break;
case CMDSN_HIGHER_THAN_EXP: case CMDSN_HIGHER_THAN_EXP:
ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn)); 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; break;
case CMDSN_LOWER_THAN_EXP: case CMDSN_LOWER_THAN_EXP:
cmd->i_state = ISTATE_REMOVE; cmd->i_state = ISTATE_REMOVE;
...@@ -309,11 +318,16 @@ int iscsit_sequence_cmd( ...@@ -309,11 +318,16 @@ int iscsit_sequence_cmd(
ret = cmdsn_ret; ret = cmdsn_ret;
break; break;
default: default:
reason = ISCSI_REASON_PROTOCOL_ERROR;
reject = true;
ret = cmdsn_ret; ret = cmdsn_ret;
break; break;
} }
mutex_unlock(&conn->sess->cmdsn_mutex); mutex_unlock(&conn->sess->cmdsn_mutex);
if (reject)
iscsit_reject_cmd(cmd, reason, buf);
return ret; return ret;
} }
EXPORT_SYMBOL(iscsit_sequence_cmd); EXPORT_SYMBOL(iscsit_sequence_cmd);
......
...@@ -13,7 +13,8 @@ extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t); ...@@ -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_datain(struct iscsi_cmd *, u32);
extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *); 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); 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 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(struct iscsi_conn *, itt_t);
extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *, extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
......
...@@ -86,4 +86,5 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *); ...@@ -86,4 +86,5 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
* From iscsi_target_util.c * From iscsi_target_util.c
*/ */
extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t); 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment