iscsi-target: Refactor ISCSI_OP_TEXT RX handling

This patch refactors ISCSI_OP_TEXT handling within iscsi-target in
order to handle iscsi_text payloads in a transport specific manner.

This includes splitting current iscsit_handle_text_cmd() into
iscsit_setup_text_cmd() and iscsit_process_text_cmd() calls, and
makes iscsit_handle_text_cmd be only used internally by traditional
iscsi socket calls.

Cc: Or Gerlitz <ogerlitz@mellanox.com>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
Nicholas Bellinger 2013-06-14 16:46:16 -07:00
parent 778de36896
commit 64534aa794
2 changed files with 94 additions and 68 deletions

View file

@ -1960,45 +1960,93 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd); EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);
/* #warning FIXME: Support Text Command parameters besides SendTargets */ /* #warning FIXME: Support Text Command parameters besides SendTargets */
static int iscsit_handle_text_cmd( int
struct iscsi_conn *conn, iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
unsigned char *buf) struct iscsi_text *hdr)
{ {
char *text_ptr, *text_in; u32 payload_length = ntoh24(hdr->dlength);
int cmdsn_ret, niov = 0, rx_got, rx_size;
u32 checksum = 0, data_crc = 0, payload_length;
u32 padding = 0, pad_bytes = 0, text_length = 0;
struct iscsi_cmd *cmd;
struct kvec iov[3];
struct iscsi_text *hdr;
hdr = (struct iscsi_text *) buf;
payload_length = ntoh24(hdr->dlength);
if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) { if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
pr_err("Unable to accept text parameter length: %u" pr_err("Unable to accept text parameter length: %u"
"greater than MaxXmitDataSegmentLength %u.\n", "greater than MaxXmitDataSegmentLength %u.\n",
payload_length, conn->conn_ops->MaxXmitDataSegmentLength); payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
buf, conn); 1, 0, (unsigned char *)hdr, cmd);
} }
pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x," pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x,"
" ExpStatSN: 0x%08x, Length: %u\n", hdr->itt, hdr->cmdsn, " ExpStatSN: 0x%08x, Length: %u\n", hdr->itt, hdr->cmdsn,
hdr->exp_statsn, payload_length); hdr->exp_statsn, payload_length);
rx_size = text_length = payload_length; cmd->iscsi_opcode = ISCSI_OP_TEXT;
if (text_length) { cmd->i_state = ISTATE_SEND_TEXTRSP;
text_in = kzalloc(text_length, GFP_KERNEL); cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
cmd->targ_xfer_tag = 0xFFFFFFFF;
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->data_direction = DMA_NONE;
return 0;
}
EXPORT_SYMBOL(iscsit_setup_text_cmd);
int
iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
struct iscsi_text *hdr)
{
int cmdsn_ret;
spin_lock_bh(&conn->cmd_lock);
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
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);
if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
1, 0, (unsigned char *)hdr, cmd);
return 0;
}
return iscsit_execute_cmd(cmd, 0);
}
EXPORT_SYMBOL(iscsit_process_text_cmd);
static int
iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
unsigned char *buf)
{
struct iscsi_text *hdr = (struct iscsi_text *)buf;
char *text_in = NULL;
u32 payload_length = ntoh24(hdr->dlength);
int rx_size, rc;
rc = iscsit_setup_text_cmd(conn, cmd, hdr);
if (rc < 0)
return rc;
rx_size = payload_length;
if (payload_length) {
char *text_ptr;
u32 checksum = 0, data_crc = 0;
u32 padding = 0, pad_bytes = 0;
int niov = 0, rx_got;
struct kvec iov[3];
text_in = kzalloc(payload_length, GFP_KERNEL);
if (!text_in) { if (!text_in) {
pr_err("Unable to allocate memory for" pr_err("Unable to allocate memory for"
" incoming text parameters\n"); " incoming text parameters\n");
return -1; goto reject;
} }
memset(iov, 0, 3 * sizeof(struct kvec)); memset(iov, 0, 3 * sizeof(struct kvec));
iov[niov].iov_base = text_in; iov[niov].iov_base = text_in;
iov[niov++].iov_len = text_length; iov[niov++].iov_len = payload_length;
padding = ((-payload_length) & 3); padding = ((-payload_length) & 3);
if (padding != 0) { if (padding != 0) {
@ -2015,14 +2063,12 @@ static int iscsit_handle_text_cmd(
} }
rx_got = rx_data(conn, &iov[0], niov, rx_size); rx_got = rx_data(conn, &iov[0], niov, rx_size);
if (rx_got != rx_size) { if (rx_got != rx_size)
kfree(text_in); goto reject;
return -1;
}
if (conn->conn_ops->DataDigest) { if (conn->conn_ops->DataDigest) {
iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, iscsit_do_crypto_hash_buf(&conn->conn_rx_hash,
text_in, text_length, text_in, payload_length,
padding, (u8 *)&pad_bytes, padding, (u8 *)&pad_bytes,
(u8 *)&data_crc); (u8 *)&data_crc);
@ -2034,8 +2080,7 @@ static int iscsit_handle_text_cmd(
pr_err("Unable to recover from" pr_err("Unable to recover from"
" Text Data digest failure while in" " Text Data digest failure while in"
" ERL=0.\n"); " ERL=0.\n");
kfree(text_in); goto reject;
return -1;
} else { } else {
/* /*
* Silently drop this PDU and let the * Silently drop this PDU and let the
@ -2050,68 +2095,40 @@ static int iscsit_handle_text_cmd(
} else { } else {
pr_debug("Got CRC32C DataDigest" pr_debug("Got CRC32C DataDigest"
" 0x%08x for %u bytes of text data.\n", " 0x%08x for %u bytes of text data.\n",
checksum, text_length); checksum, payload_length);
} }
} }
text_in[text_length - 1] = '\0'; text_in[payload_length - 1] = '\0';
pr_debug("Successfully read %d bytes of text" pr_debug("Successfully read %d bytes of text"
" data.\n", text_length); " data.\n", payload_length);
if (strncmp("SendTargets", text_in, 11) != 0) { if (strncmp("SendTargets", text_in, 11) != 0) {
pr_err("Received Text Data that is not" pr_err("Received Text Data that is not"
" SendTargets, cannot continue.\n"); " SendTargets, cannot continue.\n");
kfree(text_in); goto reject;
return -1;
} }
text_ptr = strchr(text_in, '='); text_ptr = strchr(text_in, '=');
if (!text_ptr) { if (!text_ptr) {
pr_err("No \"=\" separator found in Text Data," pr_err("No \"=\" separator found in Text Data,"
" cannot continue.\n"); " cannot continue.\n");
kfree(text_in); goto reject;
return -1;
} }
if (strncmp("=All", text_ptr, 4) != 0) { if (strncmp("=All", text_ptr, 4) != 0) {
pr_err("Unable to locate All value for" pr_err("Unable to locate All value for"
" SendTargets key, cannot continue.\n"); " SendTargets key, cannot continue.\n");
kfree(text_in); goto reject;
return -1;
} }
/*#warning Support SendTargets=(iSCSI Target Name/Nothing) values. */
kfree(text_in); kfree(text_in);
} }
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); return iscsit_process_text_cmd(conn, cmd, hdr);
if (!cmd)
return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
1, buf, conn);
cmd->iscsi_opcode = ISCSI_OP_TEXT; reject:
cmd->i_state = ISTATE_SEND_TEXTRSP; kfree(text_in);
cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0); return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt; 0, 0, buf, cmd);
cmd->targ_xfer_tag = 0xFFFFFFFF;
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->data_direction = DMA_NONE;
spin_lock_bh(&conn->cmd_lock);
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
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);
if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
1, 0, buf, cmd);
return 0;
}
return iscsit_execute_cmd(cmd, 0);
} }
EXPORT_SYMBOL(iscsit_handle_text_cmd);
int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn) int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
{ {
@ -3947,7 +3964,12 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf); ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
break; break;
case ISCSI_OP_TEXT: case ISCSI_OP_TEXT:
ret = iscsit_handle_text_cmd(conn, buf); cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
1, buf, conn);
ret = iscsit_handle_text_cmd(conn, cmd, buf);
break; break;
case ISCSI_OP_LOGOUT: case ISCSI_OP_LOGOUT:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);

View file

@ -53,6 +53,10 @@ extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *,
unsigned char *); unsigned char *);
extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *, extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *,
unsigned char *); unsigned char *);
extern int iscsit_setup_text_cmd(struct iscsi_conn *, struct iscsi_cmd *,
struct iscsi_text *);
extern int iscsit_process_text_cmd(struct iscsi_conn *, struct iscsi_cmd *,
struct iscsi_text *);
extern void iscsit_build_rsp_pdu(struct iscsi_cmd *, struct iscsi_conn *, extern void iscsit_build_rsp_pdu(struct iscsi_cmd *, struct iscsi_conn *,
bool, struct iscsi_scsi_rsp *); bool, struct iscsi_scsi_rsp *);
extern void iscsit_build_nopin_rsp(struct iscsi_cmd *, struct iscsi_conn *, extern void iscsit_build_nopin_rsp(struct iscsi_cmd *, struct iscsi_conn *,