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

Commit ba159914 authored by Nicholas Bellinger's avatar Nicholas Bellinger
Browse files

iscsi-target: Fix iscsit_add_reject* usage for iser



This patch changes iscsit_add_reject() + iscsit_add_reject_from_cmd()
usage to not sleep on iscsi_cmd->reject_comp to address a free-after-use
usage bug in v3.10 with iser-target code.

It saves ->reject_reason for use within iscsit_build_reject() so the
correct value for both transport cases.  It also drops the legacy
fail_conn parameter usage throughput iscsi-target code and adds
two iscsit_add_reject_cmd() and iscsit_reject_cmd helper functions,
along with various small cleanups.

(v2: Re-enable target_put_sess_cmd() to be called from
     iscsit_add_reject_from_cmd() for rejects invoked after
     target_get_sess_cmd() has been called)

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 3df8f68a
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -939,11 +939,6 @@ sequence_cmd:
	if (!rc && dump_payload == false && unsol_data)
		iscsit_set_unsoliticed_dataout(cmd);

	if (rc == CMDSN_ERROR_CANNOT_RECOVER)
		return iscsit_add_reject_from_cmd(
			   ISCSI_REASON_PROTOCOL_ERROR,
			   1, 0, (unsigned char *)hdr, cmd);

	return 0;
}

+103 −152
Original line number Diff line number Diff line
@@ -628,25 +628,18 @@ static void __exit iscsi_target_cleanup_module(void)
}

static int iscsit_add_reject(
	struct iscsi_conn *conn,
	u8 reason,
	int fail_conn,
	unsigned char *buf,
	struct iscsi_conn *conn)
	unsigned char *buf)
{
	struct iscsi_cmd *cmd;
	struct iscsi_reject *hdr;
	int ret;

	cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
	if (!cmd)
		return -1;

	cmd->iscsi_opcode = ISCSI_OP_REJECT;
	if (fail_conn)
		cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;

	hdr	= (struct iscsi_reject *) cmd->pdu;
	hdr->reason = reason;
	cmd->reject_reason = reason;

	cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
	if (!cmd->buf_ptr) {
@@ -662,23 +655,16 @@ static int iscsit_add_reject(
	cmd->i_state = ISTATE_SEND_REJECT;
	iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);

	ret = wait_for_completion_interruptible(&cmd->reject_comp);
	if (ret != 0)
	return -1;

	return (!fail_conn) ? 0 : -1;
}

int iscsit_add_reject_from_cmd(
static int iscsit_add_reject_from_cmd(
	struct iscsi_cmd *cmd,
	u8 reason,
	int fail_conn,
	int add_to_conn,
	unsigned char *buf,
	struct iscsi_cmd *cmd)
	bool add_to_conn,
	unsigned char *buf)
{
	struct iscsi_conn *conn;
	struct iscsi_reject *hdr;
	int ret;

	if (!cmd->conn) {
		pr_err("cmd->conn is NULL for ITT: 0x%08x\n",
@@ -688,11 +674,7 @@ int iscsit_add_reject_from_cmd(
	conn = cmd->conn;

	cmd->iscsi_opcode = ISCSI_OP_REJECT;
	if (fail_conn)
		cmd->cmd_flags |= ICF_REJECT_FAIL_CONN;

	hdr	= (struct iscsi_reject *) cmd->pdu;
	hdr->reason = reason;
	cmd->reject_reason = reason;

	cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
	if (!cmd->buf_ptr) {
@@ -709,8 +691,6 @@ int iscsit_add_reject_from_cmd(

	cmd->i_state = ISTATE_SEND_REJECT;
	iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);

	ret = wait_for_completion_interruptible(&cmd->reject_comp);
	/*
	 * Perform the kref_put now if se_cmd has already been setup by
	 * scsit_setup_scsi_cmd()
@@ -719,12 +699,19 @@ int iscsit_add_reject_from_cmd(
		pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
		target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
	}
	if (ret != 0)
	return -1;
}

static int iscsit_add_reject_cmd(struct iscsi_cmd *cmd, u8 reason,
				 unsigned char *buf)
{
	return iscsit_add_reject_from_cmd(cmd, reason, true, buf);
}

	return (!fail_conn) ? 0 : -1;
int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8 reason, unsigned char *buf)
{
	return iscsit_add_reject_from_cmd(cmd, reason, false, buf);
}
EXPORT_SYMBOL(iscsit_add_reject_from_cmd);

/*
 * Map some portion of the allocated scatterlist to an iovec, suitable for
@@ -844,8 +831,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
	    !(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
		pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL"
				" not set. Bad iSCSI Initiator.\n");
		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_BOOKMARK_INVALID, buf);
	}

	if (((hdr->flags & ISCSI_FLAG_CMD_READ) ||
@@ -865,8 +852,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
		pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE"
			" set when Expected Data Transfer Length is 0 for"
			" CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_BOOKMARK_INVALID, buf);
	}
done:

@@ -875,29 +862,29 @@ done:
		pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE"
			" MUST be set if Expected Data Transfer Length is not 0."
			" Bad iSCSI Initiator\n");
		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_BOOKMARK_INVALID, buf);
	}

	if ((hdr->flags & ISCSI_FLAG_CMD_READ) &&
	    (hdr->flags & ISCSI_FLAG_CMD_WRITE)) {
		pr_err("Bidirectional operations not supported!\n");
		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_BOOKMARK_INVALID, buf);
	}

	if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
		pr_err("Illegally set Immediate Bit in iSCSI Initiator"
				" Scsi Command PDU.\n");
		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_BOOKMARK_INVALID, buf);
	}

	if (payload_length && !conn->sess->sess_ops->ImmediateData) {
		pr_err("ImmediateData=No but DataSegmentLength=%u,"
			" protocol error.\n", payload_length);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_PROTOCOL_ERROR, buf);
	}

	if ((be32_to_cpu(hdr->data_length) == payload_length) &&
@@ -905,32 +892,32 @@ done:
		pr_err("Expected Data Transfer Length and Length of"
			" Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"
			" bit is not set protocol error\n");
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_PROTOCOL_ERROR, buf);
	}

	if (payload_length > be32_to_cpu(hdr->data_length)) {
		pr_err("DataSegmentLength: %u is greater than"
			" EDTL: %u, protocol error.\n", payload_length,
				hdr->data_length);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_PROTOCOL_ERROR, buf);
	}

	if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
		pr_err("DataSegmentLength: %u is greater than"
			" MaxXmitDataSegmentLength: %u, protocol error.\n",
			payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_PROTOCOL_ERROR, buf);
	}

	if (payload_length > conn->sess->sess_ops->FirstBurstLength) {
		pr_err("DataSegmentLength: %u is greater than"
			" FirstBurstLength: %u, protocol error.\n",
			payload_length, conn->sess->sess_ops->FirstBurstLength);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
				1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_BOOKMARK_INVALID, buf);
	}

	data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
@@ -985,9 +972,8 @@ done:

		dr = iscsit_allocate_datain_req();
		if (!dr)
			return iscsit_add_reject_from_cmd(
					ISCSI_REASON_BOOKMARK_NO_RESOURCES,
					1, 1, buf, cmd);
			return iscsit_add_reject_cmd(cmd,
					ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);

		iscsit_attach_datain_req(cmd, dr);
	}
@@ -1015,18 +1001,16 @@ done:
	cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb);
	if (cmd->sense_reason) {
		if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) {
			return iscsit_add_reject_from_cmd(
					ISCSI_REASON_BOOKMARK_NO_RESOURCES,
					1, 1, buf, cmd);
			return iscsit_add_reject_cmd(cmd,
					ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
		}

		goto attach_cmd;
	}

	if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) {
		return iscsit_add_reject_from_cmd(
			ISCSI_REASON_BOOKMARK_NO_RESOURCES,
			1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
	}

attach_cmd:
@@ -1075,10 +1059,6 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,

			target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
			return 0;
		} else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
			return iscsit_add_reject_from_cmd(
				ISCSI_REASON_PROTOCOL_ERROR,
				1, 0, (unsigned char *)hdr, cmd);
		}
	}

@@ -1149,11 +1129,6 @@ after_immediate_data:
		} else if (cmd->unsolicited_data)
			iscsit_set_unsoliticed_dataout(cmd);

		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
			return iscsit_add_reject_from_cmd(
				ISCSI_REASON_PROTOCOL_ERROR,
				1, 0, (unsigned char *)hdr, cmd);

	} else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
		/*
		 * Immediate Data failed DataCRC and ERL>=1,
@@ -1190,9 +1165,8 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
	 * traditional iSCSI block I/O.
	 */
	if (iscsit_allocate_iovecs(cmd) < 0) {
		return iscsit_add_reject_from_cmd(
				ISCSI_REASON_BOOKMARK_NO_RESOURCES,
				1, 0, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
	}
	immed_data = cmd->immediate_data;

@@ -1282,8 +1256,8 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,

	if (!payload_length) {
		pr_err("DataOUT payload is ZERO, protocol error.\n");
		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
					buf, conn);
		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
					 buf);
	}

	/* iSCSI write */
@@ -1300,8 +1274,8 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
		pr_err("DataSegmentLength: %u is greater than"
			" MaxXmitDataSegmentLength: %u\n", payload_length,
			conn->conn_ops->MaxXmitDataSegmentLength);
		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
					buf, conn);
		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
					 buf);
	}

	cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt,
@@ -1324,8 +1298,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
	if (cmd->data_direction != DMA_TO_DEVICE) {
		pr_err("Command ITT: 0x%08x received DataOUT for a"
			" NON-WRITE command.\n", cmd->init_task_tag);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
				1, 0, buf, cmd);
		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
	}
	se_cmd = &cmd->se_cmd;
	iscsit_mod_dataout_timer(cmd);
@@ -1334,8 +1307,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
		pr_err("DataOut Offset: %u, Length %u greater than"
			" iSCSI Command EDTL %u, protocol error.\n",
			hdr->offset, payload_length, cmd->se_cmd.data_length);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
				1, 0, buf, cmd);
		return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID, buf);
	}

	if (cmd->unsolicited_data) {
@@ -1543,8 +1515,8 @@ int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
	if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
		pr_err("NOPOUT ITT is reserved, but Immediate Bit is"
			" not set, protocol error.\n");
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, (unsigned char *)hdr, cmd);
		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
					 (unsigned char *)hdr);
	}

	if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
@@ -1552,8 +1524,8 @@ int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
			" greater than MaxXmitDataSegmentLength: %u, protocol"
			" error.\n", payload_length,
			conn->conn_ops->MaxXmitDataSegmentLength);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, (unsigned char *)hdr, cmd);
		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
					 (unsigned char *)hdr);
	}

	pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x,"
@@ -1612,9 +1584,7 @@ int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
			return 0;

		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
			return iscsit_add_reject_from_cmd(
					ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, (unsigned char *)hdr, cmd);
			return -1;

		return 0;
	}
@@ -1780,8 +1750,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
		pr_err("Task Management Request TASK_REASSIGN not"
			" issued as immediate command, bad iSCSI Initiator"
				"implementation\n");
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
					1, 1, buf, cmd);
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_PROTOCOL_ERROR, buf);
	}
	if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
	    be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG)
@@ -1793,9 +1763,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
	if (!cmd->tmr_req) {
		pr_err("Unable to allocate memory for"
			" Task Management command!\n");
		return iscsit_add_reject_from_cmd(
		return iscsit_add_reject_cmd(cmd,
					     ISCSI_REASON_BOOKMARK_NO_RESOURCES,
			1, 1, buf, cmd);
					     buf);
	}

	/*
@@ -1837,17 +1807,15 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
		default:
			pr_err("Unknown iSCSI TMR Function:"
			       " 0x%02x\n", function);
			return iscsit_add_reject_from_cmd(
				ISCSI_REASON_BOOKMARK_NO_RESOURCES,
				1, 1, buf, cmd);
			return iscsit_add_reject_cmd(cmd,
				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
		}

		ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req,
					 tcm_function, GFP_KERNEL);
		if (ret < 0)
			return iscsit_add_reject_from_cmd(
				ISCSI_REASON_BOOKMARK_NO_RESOURCES,
				1, 1, buf, cmd);
			return iscsit_add_reject_cmd(cmd,
				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);

		cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;
	}
@@ -1906,9 +1874,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
			break;

		if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0)
			return iscsit_add_reject_from_cmd(
					ISCSI_REASON_BOOKMARK_INVALID, 1, 1,
					buf, cmd);
			return iscsit_add_reject_cmd(cmd,
					ISCSI_REASON_BOOKMARK_INVALID, buf);
		break;
	default:
		pr_err("Unknown TMR function: 0x%02x, protocol"
@@ -1932,9 +1899,7 @@ attach:
		else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
			return 0;
		else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
			return iscsit_add_reject_from_cmd(
					ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, buf, cmd);
			return -1;
	}
	iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));

@@ -1970,8 +1935,8 @@ iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
		pr_err("Unable to accept text parameter length: %u"
			"greater than MaxXmitDataSegmentLength %u.\n",
		       payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
					1, 0, (unsigned char *)hdr, cmd);
		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
					 (unsigned char *)hdr);
	}

	pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x,"
@@ -2033,17 +1998,16 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
	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 -1;

		return 0;
	}

	return iscsit_execute_cmd(cmd, 0);

reject:
	return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
					  0, 0, (unsigned char *)hdr, cmd);
	return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR,
				 (unsigned char *)hdr);
}
EXPORT_SYMBOL(iscsit_process_text_cmd);

@@ -2139,8 +2103,7 @@ iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
reject:
	kfree(cmd->text_in_ptr);
	cmd->text_in_ptr = NULL;
	return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
					  0, 0, buf, cmd);
	return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);
}
EXPORT_SYMBOL(iscsit_handle_text_cmd);

@@ -2322,13 +2285,10 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
			return ret;
	} else {
		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
		if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
		if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
			logout_remove = 0;
		} else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
			return iscsit_add_reject_from_cmd(
				ISCSI_REASON_PROTOCOL_ERROR,
				1, 0, buf, cmd);
		}
		else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
			return -1;
	}

	return logout_remove;
@@ -2352,8 +2312,8 @@ static int iscsit_handle_snack(
	if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
		pr_err("Initiator sent SNACK request while in"
			" ErrorRecoveryLevel=0.\n");
		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
					buf, conn);
		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
					 buf);
	}
	/*
	 * SNACK_DATA and SNACK_R2T are both 0,  so check which function to
@@ -2377,13 +2337,13 @@ static int iscsit_handle_snack(
	case ISCSI_FLAG_SNACK_TYPE_RDATA:
		/* FIXME: Support R-Data SNACK */
		pr_err("R-Data SNACK Not Supported.\n");
		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
					buf, conn);
		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
					 buf);
	default:
		pr_err("Unknown SNACK type 0x%02x, protocol"
			" error.\n", hdr->flags & 0x0f);
		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
					buf, conn);
		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
					 buf);
	}

	return 0;
@@ -2455,14 +2415,14 @@ static int iscsit_handle_immediate_data(
				pr_err("Unable to recover from"
					" Immediate Data digest failure while"
					" in ERL=0.\n");
				iscsit_add_reject_from_cmd(
				iscsit_reject_cmd(cmd,
						ISCSI_REASON_DATA_DIGEST_ERROR,
						1, 0, (unsigned char *)hdr, cmd);
						(unsigned char *)hdr);
				return IMMEDIATE_DATA_CANNOT_RECOVER;
			} else {
				iscsit_add_reject_from_cmd(
				iscsit_reject_cmd(cmd,
						ISCSI_REASON_DATA_DIGEST_ERROR,
						0, 0, (unsigned char *)hdr, cmd);
						(unsigned char *)hdr);
				return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
			}
		} else {
@@ -3595,6 +3555,7 @@ iscsit_build_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
		    struct iscsi_reject *hdr)
{
	hdr->opcode		= ISCSI_OP_REJECT;
	hdr->reason		= cmd->reject_reason;
	hdr->flags		|= ISCSI_FLAG_CMD_FINAL;
	hton24(hdr->dlength, ISCSI_HDR_LEN);
	hdr->ffffffff		= cpu_to_be32(0xffffffff);
@@ -3868,18 +3829,11 @@ check_rsp_state:
	case ISTATE_SEND_STATUS_RECOVERY:
	case ISTATE_SEND_TEXTRSP:
	case ISTATE_SEND_TASKMGTRSP:
	case ISTATE_SEND_REJECT:
		spin_lock_bh(&cmd->istate_lock);
		cmd->i_state = ISTATE_SENT_STATUS;
		spin_unlock_bh(&cmd->istate_lock);
		break;
	case ISTATE_SEND_REJECT:
		if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
			cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
			complete(&cmd->reject_comp);
			goto err;
		}
		complete(&cmd->reject_comp);
		break;
	default:
		pr_err("Unknown Opcode: 0x%02x ITT:"
		       " 0x%08x, i_state: %d on CID: %hu\n",
@@ -3984,8 +3938,7 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
	case ISCSI_OP_SCSI_CMD:
		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
		if (!cmd)
			return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
						1, buf, conn);
			goto reject;

		ret = iscsit_handle_scsi_cmd(conn, cmd, buf);
		break;
@@ -3997,32 +3950,28 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
		if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
			cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
			if (!cmd)
				return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
						1, buf, conn);
				goto reject;
		}
		ret = iscsit_handle_nop_out(conn, cmd, buf);
		break;
	case ISCSI_OP_SCSI_TMFUNC:
		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
		if (!cmd)
			return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
						1, buf, conn);
			goto reject;

		ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
		break;
	case ISCSI_OP_TEXT:
		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
		if (!cmd)
			return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
						1, buf, conn);
			goto reject;

		ret = iscsit_handle_text_cmd(conn, cmd, buf);
		break;
	case ISCSI_OP_LOGOUT:
		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
		if (!cmd)
			return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
						1, buf, conn);
			goto reject;

		ret = iscsit_handle_logout_cmd(conn, cmd, buf);
		if (ret > 0)
@@ -4054,6 +4003,8 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
	}

	return ret;
reject:
	return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
}

int iscsi_target_rx_thread(void *arg)
@@ -4148,8 +4099,8 @@ restart:
		    (!(opcode & ISCSI_OP_LOGOUT)))) {
			pr_err("Received illegal iSCSI Opcode: 0x%02x"
			" while in Discovery Session, rejecting.\n", opcode);
			iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
					buffer, conn);
			iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR,
					  buffer);
			goto transport_err;
		}

+1 −1
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,
extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
				struct iscsi_portal_group *);
extern int iscsit_del_np(struct iscsi_np *);
extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *);
extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *);
extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *);
+4 −4
Original line number Diff line number Diff line
@@ -132,9 +132,8 @@ enum cmd_flags_table {
	ICF_CONTIG_MEMORY			= 0x00000020,
	ICF_ATTACHED_TO_RQUEUE			= 0x00000040,
	ICF_OOO_CMDSN				= 0x00000080,
	ICF_REJECT_FAIL_CONN			= 0x00000100,
	IFC_SENDTARGETS_ALL			= 0x00000200,
	IFC_SENDTARGETS_SINGLE			= 0x00000400,
	IFC_SENDTARGETS_ALL			= 0x00000100,
	IFC_SENDTARGETS_SINGLE			= 0x00000200,
};

/* struct iscsi_cmd->i_state */
@@ -368,6 +367,8 @@ struct iscsi_cmd {
	u8			maxcmdsn_inc;
	/* Immediate Unsolicited Dataout */
	u8			unsolicited_data;
	/* Reject reason code */
	u8			reject_reason;
	/* CID contained in logout PDU when opcode == ISCSI_INIT_LOGOUT_CMND */
	u16			logout_cid;
	/* Command flags */
@@ -450,7 +451,6 @@ struct iscsi_cmd {
	struct list_head	datain_list;
	/* R2T List */
	struct list_head	cmd_r2t_list;
	struct completion	reject_comp;
	/* Timer for DataOUT */
	struct timer_list	dataout_timer;
	/* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */
+3 −4
Original line number Diff line number Diff line
@@ -746,13 +746,12 @@ int iscsit_check_post_dataout(
		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
			pr_err("Unable to recover from DataOUT CRC"
				" failure while ERL=0, closing session.\n");
			iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
					1, 0, buf, cmd);
			iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR,
					  buf);
			return DATAOUT_CANNOT_RECOVER;
		}

		iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR,
				0, 0, buf, cmd);
		iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, buf);
		return iscsit_dataout_post_crc_failed(cmd, buf);
	}
}
Loading