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

Commit 6f3c0e69 authored by Andy Grover's avatar Andy Grover Committed by Nicholas Bellinger
Browse files

target/iscsi: Refactor target_tx_thread immediate+response queue loops



Immediate queue:

Consolidate down to one switch statement by moving send_tx_data and stuff
from second switch into the first switch, or the functions the first switch
calls.

Response queue:

Do not lock istate_lock except directly around i_state modifications.

Put entire ISTATE_SEND_DATAIN path within first switch statement, in prep
for further refactoring.

All other cases set use_misc = 1 and will not be using sendpage, so just
use send_tx_data for these and set use_misc param to 1.

map_sg, sent_status, use_misc, and se_cmd vars no longer needed.

Then put immediate and response handling in separate functions in order
to get iscsi_target_tx_thread down to where it fits on a page.

Signed-off-by: default avatarAndy Grover <agrover@redhat.com>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 4580cf38
Loading
Loading
Loading
Loading
+244 −243
Original line number Diff line number Diff line
@@ -2434,10 +2434,19 @@ static int iscsit_send_conn_drop_async_message(
	return 0;
}

static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn)
{
	if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) ||
	    (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) {
		wait_for_completion_interruptible_timeout(
					&conn->tx_half_close_comp,
					ISCSI_TX_THREAD_TCP_TIMEOUT * HZ);
	}
}

static int iscsit_send_data_in(
	struct iscsi_cmd *cmd,
	struct iscsi_conn *conn,
	int *eodr)
	struct iscsi_conn *conn)
{
	int iov_ret = 0, set_statsn = 0;
	u32 iov_count = 0, tx_size = 0;
@@ -2445,6 +2454,8 @@ static int iscsit_send_data_in(
	struct iscsi_datain_req *dr;
	struct iscsi_data_rsp *hdr;
	struct kvec *iov;
	int eodr = 0;
	int ret;

	memset(&datain, 0, sizeof(struct iscsi_datain));
	dr = iscsit_get_datain_values(cmd, &datain);
@@ -2577,13 +2588,26 @@ static int iscsit_send_data_in(
		cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn),
		ntohl(hdr->offset), datain.length, conn->cid);

	/* sendpage is preferred but can't insert markers */
	if (!conn->conn_ops->IFMarker)
		ret = iscsit_fe_sendpage_sg(cmd, conn);
	else
		ret = iscsit_send_tx_data(cmd, conn, 0);

	iscsit_unmap_iovec(cmd);

	if (ret < 0) {
		iscsit_tx_thread_wait_for_tcp(conn);
		return ret;
	}

	if (dr->dr_complete) {
		*eodr = (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ?
		eodr = (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ?
				2 : 1;
		iscsit_free_datain_req(cmd, dr);
	}

	return 0;
	return eodr;
}

static int iscsit_send_logout_response(
@@ -2715,6 +2739,7 @@ static int iscsit_send_unsolicited_nopin(
{
	int tx_size = ISCSI_HDR_LEN;
	struct iscsi_nopin *hdr;
	int ret;

	hdr			= (struct iscsi_nopin *) cmd->pdu;
	memset(hdr, 0, ISCSI_HDR_LEN);
@@ -2747,6 +2772,17 @@ static int iscsit_send_unsolicited_nopin(
	pr_debug("Sending Unsolicited NOPIN TTT: 0x%08x StatSN:"
		" 0x%08x CID: %hu\n", hdr->ttt, cmd->stat_sn, conn->cid);

	ret = iscsit_send_tx_data(cmd, conn, 1);
	if (ret < 0) {
		iscsit_tx_thread_wait_for_tcp(conn);
		return ret;
	}

	spin_lock_bh(&cmd->istate_lock);
	cmd->i_state = want_response ?
		ISTATE_SENT_NOPIN_WANT_RESPONSE : ISTATE_SENT_STATUS;
	spin_unlock_bh(&cmd->istate_lock);

	return 0;
}

@@ -2837,13 +2873,14 @@ static int iscsit_send_nopin_response(
	return 0;
}

int iscsit_send_r2t(
static int iscsit_send_r2t(
	struct iscsi_cmd *cmd,
	struct iscsi_conn *conn)
{
	int tx_size = 0;
	struct iscsi_r2t *r2t;
	struct iscsi_r2t_rsp *hdr;
	int ret;

	r2t = iscsit_get_r2t_from_list(cmd);
	if (!r2t)
@@ -2899,6 +2936,16 @@ int iscsit_send_r2t(
	r2t->sent_r2t = 1;
	spin_unlock_bh(&cmd->r2t_lock);

	ret = iscsit_send_tx_data(cmd, conn, 1);
	if (ret < 0) {
		iscsit_tx_thread_wait_for_tcp(conn);
		return ret;
	}

	spin_lock_bh(&cmd->dataout_timeout_lock);
	iscsit_start_dataout_timer(cmd, conn);
	spin_unlock_bh(&cmd->dataout_timeout_lock);

	return 0;
}

@@ -3407,16 +3454,6 @@ static int iscsit_send_reject(
	return 0;
}

static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn)
{
	if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) ||
	    (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) {
		wait_for_completion_interruptible_timeout(
					&conn->tx_half_close_comp,
					ISCSI_TX_THREAD_TCP_TIMEOUT * HZ);
	}
}

void iscsit_thread_get_cpumask(struct iscsi_conn *conn)
{
	struct iscsi_thread_set *ts = conn->thread_set;
@@ -3472,43 +3509,12 @@ static inline void iscsit_thread_check_cpumask(
	set_cpus_allowed_ptr(p, conn->conn_cpumask);
}

int iscsi_target_tx_thread(void *arg)
static int handle_immediate_queue(struct iscsi_conn *conn)
{
	struct iscsi_queue_req *qr;
	struct iscsi_cmd *cmd;
	u8 state;
	int eodr = 0;
	int ret = 0;
	int sent_status = 0;
	int use_misc = 0;
	int map_sg = 0;
	struct iscsi_cmd *cmd = NULL;
	struct iscsi_conn *conn;
	struct iscsi_queue_req *qr = NULL;
	struct iscsi_thread_set *ts = arg;
	/*
	 * Allow ourselves to be interrupted by SIGINT so that a
	 * connection recovery / failure event can be triggered externally.
	 */
	allow_signal(SIGINT);

restart:
	conn = iscsi_tx_thread_pre_handler(ts);
	if (!conn)
		goto out;

	eodr = map_sg = ret = sent_status = use_misc = 0;

	while (!kthread_should_stop()) {
		/*
		 * Ensure that both TX and RX per connection kthreads
		 * are scheduled to run on the same CPU.
		 */
		iscsit_thread_check_cpumask(conn, current, 1);

		schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);

		if ((ts->status == ISCSI_THREAD_SET_RESET) ||
		     signal_pending(current))
			goto transport_err;
	int ret;

	while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) {
		atomic_set(&conn->check_immediate_queue, 0);
@@ -3519,6 +3525,8 @@ int iscsi_target_tx_thread(void *arg)
		switch (state) {
		case ISTATE_SEND_R2T:
			ret = iscsit_send_r2t(cmd, conn);
			if (ret < 0)
				goto err;
			break;
		case ISTATE_REMOVE:
			if (cmd->data_direction == DMA_TO_DEVICE)
@@ -3534,95 +3542,86 @@ int iscsi_target_tx_thread(void *arg)
			iscsit_mod_nopin_response_timer(conn);
			ret = iscsit_send_unsolicited_nopin(cmd,
							    conn, 1);
			if (ret < 0)
				goto err;
			break;
		case ISTATE_SEND_NOPIN_NO_RESPONSE:
			ret = iscsit_send_unsolicited_nopin(cmd,
							    conn, 0);
			if (ret < 0)
				goto err;
			break;
		default:
			pr_err("Unknown Opcode: 0x%02x ITT:"
			       " 0x%08x, i_state: %d on CID: %hu\n",
			       cmd->iscsi_opcode, cmd->init_task_tag, state,
			       conn->cid);
				goto transport_err;
			goto err;
		}
			if (ret < 0)
				goto transport_err;

			if (iscsit_send_tx_data(cmd, conn, 1) < 0) {
				iscsit_tx_thread_wait_for_tcp(conn);
				goto transport_err;
	}

			switch (state) {
			case ISTATE_SEND_R2T:
				spin_lock_bh(&cmd->dataout_timeout_lock);
				iscsit_start_dataout_timer(cmd, conn);
				spin_unlock_bh(&cmd->dataout_timeout_lock);
				break;
			case ISTATE_SEND_NOPIN_WANT_RESPONSE:
				spin_lock_bh(&cmd->istate_lock);
				cmd->i_state = ISTATE_SENT_NOPIN_WANT_RESPONSE;
				spin_unlock_bh(&cmd->istate_lock);
				break;
			case ISTATE_SEND_NOPIN_NO_RESPONSE:
				spin_lock_bh(&cmd->istate_lock);
				cmd->i_state = ISTATE_SENT_STATUS;
				spin_unlock_bh(&cmd->istate_lock);
				break;
			default:
				pr_err("Unknown Opcode: 0x%02x ITT:"
					" 0x%08x, i_state: %d on CID: %hu\n",
					cmd->iscsi_opcode, cmd->init_task_tag,
					state, conn->cid);
				goto transport_err;
			}
	return 0;

err:
	return -1;
}

static int handle_response_queue(struct iscsi_conn *conn)
{
	struct iscsi_queue_req *qr;
	struct iscsi_cmd *cmd;
	u8 state;
	int ret;

	while ((qr = iscsit_get_cmd_from_response_queue(conn))) {
		cmd = qr->cmd;
		state = qr->state;
		kmem_cache_free(lio_qr_cache, qr);

			spin_lock_bh(&cmd->istate_lock);
check_rsp_state:
		switch (state) {
		case ISTATE_SEND_DATAIN:
			ret = iscsit_send_data_in(cmd, conn);
			if (ret < 0)
				goto err;
			else if (!ret)
				/* more drs */
				goto check_rsp_state;
			else if (ret == 1) {
				/* all done */
				spin_lock_bh(&cmd->istate_lock);
				cmd->i_state = ISTATE_SENT_STATUS;
				spin_unlock_bh(&cmd->istate_lock);
				continue;
			} else if (ret == 2) {
				/* Still must send status,
				   SCF_TRANSPORT_TASK_SENSE was set */
				spin_lock_bh(&cmd->istate_lock);
				cmd->i_state = ISTATE_SEND_STATUS;
				spin_unlock_bh(&cmd->istate_lock);
				ret = iscsit_send_data_in(cmd, conn,
							  &eodr);
				map_sg = 1;
				state = ISTATE_SEND_STATUS;
				goto check_rsp_state;
			}

			break;
		case ISTATE_SEND_STATUS:
		case ISTATE_SEND_STATUS_RECOVERY:
				spin_unlock_bh(&cmd->istate_lock);
				use_misc = 1;
			ret = iscsit_send_status(cmd, conn);
			break;
		case ISTATE_SEND_LOGOUTRSP:
				spin_unlock_bh(&cmd->istate_lock);
				use_misc = 1;
			ret = iscsit_send_logout_response(cmd, conn);
			break;
		case ISTATE_SEND_ASYNCMSG:
				spin_unlock_bh(&cmd->istate_lock);
				use_misc = 1;
			ret = iscsit_send_conn_drop_async_message(
				cmd, conn);
			break;
		case ISTATE_SEND_NOPIN:
				spin_unlock_bh(&cmd->istate_lock);
				use_misc = 1;
			ret = iscsit_send_nopin_response(cmd, conn);
			break;
		case ISTATE_SEND_REJECT:
				spin_unlock_bh(&cmd->istate_lock);
				use_misc = 1;
			ret = iscsit_send_reject(cmd, conn);
			break;
		case ISTATE_SEND_TASKMGTRSP:
				spin_unlock_bh(&cmd->istate_lock);
				use_misc = 1;
			ret = iscsit_send_task_mgt_rsp(cmd, conn);
			if (ret != 0)
				break;
@@ -3631,8 +3630,6 @@ int iscsi_target_tx_thread(void *arg)
				iscsit_fall_back_to_erl0(conn->sess);
			break;
		case ISTATE_SEND_TEXTRSP:
				spin_unlock_bh(&cmd->istate_lock);
				use_misc = 1;
			ret = iscsit_send_text_rsp(cmd, conn);
			break;
		default:
@@ -3640,97 +3637,101 @@ int iscsi_target_tx_thread(void *arg)
			       " 0x%08x, i_state: %d on CID: %hu\n",
			       cmd->iscsi_opcode, cmd->init_task_tag,
			       state, conn->cid);
				spin_unlock_bh(&cmd->istate_lock);
				goto transport_err;
			goto err;
		}
		if (ret < 0)
				goto transport_err;
			goto err;

			if (map_sg && !conn->conn_ops->IFMarker) {
				if (iscsit_fe_sendpage_sg(cmd, conn) < 0) {
					iscsit_tx_thread_wait_for_tcp(conn);
					iscsit_unmap_iovec(cmd);
					goto transport_err;
				}
			} else {
				if (iscsit_send_tx_data(cmd, conn, use_misc) < 0) {
		if (iscsit_send_tx_data(cmd, conn, 1) < 0) {
			iscsit_tx_thread_wait_for_tcp(conn);
			iscsit_unmap_iovec(cmd);
					goto transport_err;
				}
			goto err;
		}
			map_sg = 0;
		iscsit_unmap_iovec(cmd);

			spin_lock_bh(&cmd->istate_lock);
		switch (state) {
			case ISTATE_SEND_DATAIN:
				if (!eodr)
					goto check_rsp_state;

				if (eodr == 1) {
					cmd->i_state = ISTATE_SENT_LAST_DATAIN;
					sent_status = 1;
					eodr = use_misc = 0;
				} else if (eodr == 2) {
					cmd->i_state = state =
							ISTATE_SEND_STATUS;
					sent_status = 0;
					eodr = use_misc = 0;
					goto check_rsp_state;
				}
				break;
		case ISTATE_SEND_LOGOUTRSP:
			if (!iscsit_logout_post_handler(cmd, conn))
				goto restart;
			/* fall through */
		case ISTATE_SEND_STATUS:
				use_misc = 0;
				sent_status = 1;
				break;
		case ISTATE_SEND_ASYNCMSG:
		case ISTATE_SEND_NOPIN:
		case ISTATE_SEND_STATUS_RECOVERY:
		case ISTATE_SEND_TEXTRSP:
				use_misc = 0;
				sent_status = 1;
		case ISTATE_SEND_TASKMGTRSP:
			spin_lock_bh(&cmd->istate_lock);
			cmd->i_state = ISTATE_SENT_STATUS;
			spin_unlock_bh(&cmd->istate_lock);
			break;
		case ISTATE_SEND_REJECT:
				use_misc = 0;
			if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
				cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
					spin_unlock_bh(&cmd->istate_lock);
				complete(&cmd->reject_comp);
					goto transport_err;
				goto err;
			}
			complete(&cmd->reject_comp);
			break;
			case ISTATE_SEND_TASKMGTRSP:
				use_misc = 0;
				sent_status = 1;
				break;
			case ISTATE_SEND_LOGOUTRSP:
				spin_unlock_bh(&cmd->istate_lock);
				if (!iscsit_logout_post_handler(cmd, conn))
					goto restart;
				spin_lock_bh(&cmd->istate_lock);
				use_misc = 0;
				sent_status = 1;
				break;
		default:
			pr_err("Unknown Opcode: 0x%02x ITT:"
			       " 0x%08x, i_state: %d on CID: %hu\n",
			       cmd->iscsi_opcode, cmd->init_task_tag,
			       cmd->i_state, conn->cid);
				spin_unlock_bh(&cmd->istate_lock);
				goto transport_err;
			goto err;
		}

			if (sent_status) {
				cmd->i_state = ISTATE_SENT_STATUS;
				sent_status = 0;
			}
			spin_unlock_bh(&cmd->istate_lock);

		if (atomic_read(&conn->check_immediate_queue))
			break;
	}

	return 0;

err:
	return -1;
restart:
	return -EAGAIN;
}

int iscsi_target_tx_thread(void *arg)
{
	int ret = 0;
	struct iscsi_conn *conn;
	struct iscsi_thread_set *ts = arg;
	/*
	 * Allow ourselves to be interrupted by SIGINT so that a
	 * connection recovery / failure event can be triggered externally.
	 */
	allow_signal(SIGINT);

restart:
	conn = iscsi_tx_thread_pre_handler(ts);
	if (!conn)
		goto out;

	ret = 0;

	while (!kthread_should_stop()) {
		/*
		 * Ensure that both TX and RX per connection kthreads
		 * are scheduled to run on the same CPU.
		 */
		iscsit_thread_check_cpumask(conn, current, 1);

		schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);

		if ((ts->status == ISCSI_THREAD_SET_RESET) ||
		     signal_pending(current))
			goto transport_err;

		ret = handle_immediate_queue(conn);
		if (ret < 0)
			goto transport_err;

		ret = handle_response_queue(conn);
		if (ret == -EAGAIN)
			goto restart;
		else if (ret < 0)
			goto transport_err;
	}

transport_err:
+0 −1
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_send_async_msg(struct iscsi_conn *, u16, u8, u8);
extern int iscsit_send_r2t(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_build_r2ts_for_cmd(struct iscsi_cmd *, struct iscsi_conn *, int);
extern void iscsit_thread_get_cpumask(struct iscsi_conn *);
extern int iscsi_target_tx_thread(void *);