Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 64534aa7 authored by Nicholas Bellinger's avatar Nicholas Bellinger
Browse files

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: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 778de368
Loading
Loading
Loading
Loading
+90 −68
Original line number Original line Diff line number Diff line
@@ -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;
	cmd->i_state		= ISTATE_SEND_TEXTRSP;
	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;

	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)) {
reject:
		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
	kfree(text_in);
		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
	return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
			return iscsit_add_reject_from_cmd(
					  0, 0, buf, 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);
+4 −0
Original line number Original line Diff line number Diff line
@@ -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 *,