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: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
Родитель
ba15991408
Коммит
561bf15892
|
@ -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,
|
||||||
* 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,
|
||||||
* 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,
|
||||||
* 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
|
||||||
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 @@ after_immediate_data:
|
||||||
* 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,
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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 @@ attach:
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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(
|
||||||
|
|
||||||
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(
|
||||||
|
|
||||||
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
|
||||||
* 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(
|
||||||
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(
|
||||||
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);
|
||||||
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 *);
|
||||||
* 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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче