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

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

iscsi-target: Initial traditional TCP conversion to iscsit_transport



This patch performs the initial conversion of existing traditional iscsi
to use iscsit_transport API callers.  This includes:

- iscsi-np cleanups for iscsit_transport_type
- Add iscsi-np transport calls w/ ->iscsit_setup_up() and ->iscsit_free_np()
- Convert login thread process context to use ->iscsit_accept_np() for
  connections with pre-allocated struct iscsi_conn
- Convert existing socket accept code to iscsit_accept_np()
- Convert login RX/TX callers to use ->iscsit_get_login_rx() and
  ->iscsit_put_login_tx() to exchange request/response PDUs
- Convert existing socket login RX/TX calls into iscsit_get_login_rx()
  and iscsit_put_login_tx()
- Change iscsit_close_connection() to invoke ->iscsit_free_conn() +
  iscsit_put_transport() calls.
- Add iscsit_register_transport() + iscsit_unregister_transport() calls
  to module init/exit

v4 changes:

- Add missing iscsit_put_transport() call in iscsi_target_setup_login_socket()
  failure case

v2 changes:

- Update module init/exit to use register_transport() + unregister_transport()

Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 3f993063
Loading
Loading
Loading
Loading
+28 −7
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@
#include "iscsi_target_device.h"
#include "iscsi_target_stat.h"

#include <target/iscsi/iscsi_transport.h>

static LIST_HEAD(g_tiqn_list);
static LIST_HEAD(g_np_list);
static DEFINE_SPINLOCK(tiqn_lock);
@@ -401,8 +403,7 @@ struct iscsi_np *iscsit_add_np(
	spin_unlock_bh(&np_lock);

	pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
		np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
		"TCP" : "SCTP");
		np->np_ip, np->np_port, np->np_transport->name);

	return np;
}
@@ -441,11 +442,10 @@ int iscsit_reset_np_thread(
	return 0;
}

static int iscsit_del_np_comm(struct iscsi_np *np)
static void iscsit_free_np(struct iscsi_np *np)
{
	if (np->np_socket)
		sock_release(np->np_socket);
	return 0;
}

int iscsit_del_np(struct iscsi_np *np)
@@ -467,20 +467,32 @@ int iscsit_del_np(struct iscsi_np *np)
		send_sig(SIGINT, np->np_thread, 1);
		kthread_stop(np->np_thread);
	}
	iscsit_del_np_comm(np);

	np->np_transport->iscsit_free_np(np);

	spin_lock_bh(&np_lock);
	list_del(&np->np_list);
	spin_unlock_bh(&np_lock);

	pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
		np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
		"TCP" : "SCTP");
		np->np_ip, np->np_port, np->np_transport->name);

	iscsit_put_transport(np->np_transport);
	kfree(np);
	return 0;
}

static struct iscsit_transport iscsi_target_transport = {
	.name			= "iSCSI/TCP",
	.transport_type		= ISCSI_TCP,
	.owner			= NULL,
	.iscsit_setup_np	= iscsit_setup_np,
	.iscsit_accept_np	= iscsit_accept_np,
	.iscsit_free_np		= iscsit_free_np,
	.iscsit_get_login_rx	= iscsit_get_login_rx,
	.iscsit_put_login_tx	= iscsit_put_login_tx,
};

static int __init iscsi_target_init_module(void)
{
	int ret = 0;
@@ -557,6 +569,8 @@ static int __init iscsi_target_init_module(void)
		goto ooo_out;
	}

	iscsit_register_transport(&iscsi_target_transport);

	if (iscsit_load_discovery_tpg() < 0)
		goto r2t_out;

@@ -587,6 +601,7 @@ static void __exit iscsi_target_cleanup_module(void)
	iscsi_deallocate_thread_sets();
	iscsi_thread_set_free();
	iscsit_release_discovery_tpg();
	iscsit_unregister_transport(&iscsi_target_transport);
	kmem_cache_destroy(lio_cmd_cache);
	kmem_cache_destroy(lio_qr_cache);
	kmem_cache_destroy(lio_dr_cache);
@@ -4053,6 +4068,12 @@ int iscsit_close_connection(

	if (conn->sock)
		sock_release(conn->sock);

	if (conn->conn_transport->iscsit_free_conn)
		conn->conn_transport->iscsit_free_conn(conn);

	iscsit_put_transport(conn->conn_transport);

	conn->thread_set = NULL;

	pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
+12 −3
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@

#define ISCSI_IOV_DATA_BUFFER		5

enum tpg_np_network_transport_table {
enum iscsit_transport_type {
	ISCSI_TCP				= 0,
	ISCSI_SCTP_TCP				= 1,
	ISCSI_SCTP_UDP				= 2,
@@ -503,6 +503,7 @@ struct iscsi_conn {
	u16			login_port;
	u16			local_port;
	int			net_size;
	int			login_family;
	u32			auth_id;
	u32			conn_flags;
	/* Used for iscsi_tx_login_rsp() */
@@ -562,9 +563,12 @@ struct iscsi_conn {
	struct list_head	immed_queue_list;
	struct list_head	response_queue_list;
	struct iscsi_conn_ops	*conn_ops;
	struct iscsi_login	*conn_login;
	struct iscsit_transport *conn_transport;
	struct iscsi_param_list	*param_list;
	/* Used for per connection auth state machine */
	void			*auth_protocol;
	void			*context;
	struct iscsi_login_thread_s *login_thread;
	struct iscsi_portal_group *tpg;
	/* Pointer to parent session */
@@ -663,6 +667,8 @@ struct iscsi_login {
	u8 first_request;
	u8 version_min;
	u8 version_max;
	u8 login_complete;
	u8 login_failed;
	char isid[6];
	u32 cmd_sn;
	itt_t init_task_tag;
@@ -670,10 +676,11 @@ struct iscsi_login {
	u32 rsp_length;
	u16 cid;
	u16 tsih;
	char *req;
	char *rsp;
	char req[ISCSI_HDR_LEN];
	char rsp[ISCSI_HDR_LEN];
	char *req_buf;
	char *rsp_buf;
	struct iscsi_conn *conn;
} ____cacheline_aligned;

struct iscsi_node_attrib {
@@ -754,6 +761,8 @@ struct iscsi_np {
	struct task_struct	*np_thread;
	struct timer_list	np_login_timer;
	struct iscsi_portal_group *np_login_tpg;
	void			*np_context;
	struct iscsit_transport *np_transport;
	struct list_head	np_list;
} ____cacheline_aligned;

+289 −127
Original line number Diff line number Diff line
@@ -39,8 +39,39 @@
#include "iscsi_target.h"
#include "iscsi_target_parameters.h"

static int iscsi_login_init_conn(struct iscsi_conn *conn)
#include <target/iscsi/iscsi_transport.h>

static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
{
	struct iscsi_login *login;

	login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
	if (!login) {
		pr_err("Unable to allocate memory for struct iscsi_login.\n");
		return NULL;
	}
	login->conn = conn;
	login->first_request = 1;

	login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
	if (!login->req_buf) {
		pr_err("Unable to allocate memory for response buffer.\n");
		goto out_login;
	}

	login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
	if (!login->rsp_buf) {
		pr_err("Unable to allocate memory for request buffer.\n");
		goto out_req_buf;
	}

	conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
	if (!conn->conn_ops) {
		pr_err("Unable to allocate memory for"
			" struct iscsi_conn_ops.\n");
		goto out_rsp_buf;
	}

	init_waitqueue_head(&conn->queues_wq);
	INIT_LIST_HEAD(&conn->conn_list);
	INIT_LIST_HEAD(&conn->conn_cmd_list);
@@ -62,10 +93,21 @@ static int iscsi_login_init_conn(struct iscsi_conn *conn)

	if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) {
		pr_err("Unable to allocate conn->conn_cpumask\n");
		return -ENOMEM;
		goto out_conn_ops;
	}
	conn->conn_login = login;

	return 0;
	return login;

out_conn_ops:
	kfree(conn->conn_ops);
out_rsp_buf:
	kfree(login->rsp_buf);
out_req_buf:
	kfree(login->req_buf);
out_login:
	kfree(login);
	return NULL;
}

/*
@@ -573,10 +615,13 @@ int iscsi_login_post_auth_non_zero_tsih(

static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
{
#warning FIXME: Reenable iscsit_start_nopin_timer
#if 0
	struct iscsi_session *sess = conn->sess;

	if (!sess->sess_ops->SessionType)
		iscsit_start_nopin_timer(conn);
#endif
}

static int iscsi_post_login_handler(
@@ -632,7 +677,13 @@ static int iscsi_post_login_handler(
		spin_unlock_bh(&sess->conn_lock);

		iscsi_post_login_start_timers(conn);

		if (conn->conn_transport == ISCSI_TCP) {
			iscsi_activate_thread_set(conn, ts);
		} else {
			printk("Not calling iscsi_activate_thread_set....\n");
			dump_stack();
		}
		/*
		 * Determine CPU mask to ensure connection's RX and TX kthreads
		 * are scheduled on the same CPU.
@@ -761,11 +812,11 @@ static void iscsi_stop_login_thread_timer(struct iscsi_np *np)
	spin_unlock_bh(&np->np_thread_lock);
}

int iscsi_target_setup_login_socket(
int iscsit_setup_np(
	struct iscsi_np *np,
	struct __kernel_sockaddr_storage *sockaddr)
{
	struct socket *sock;
	struct socket *sock = NULL;
	int backlog = 5, ret, opt = 0, len;

	switch (np->np_network_transport) {
@@ -781,15 +832,15 @@ int iscsi_target_setup_login_socket(
		np->np_ip_proto = IPPROTO_SCTP;
		np->np_sock_type = SOCK_SEQPACKET;
		break;
	case ISCSI_IWARP_TCP:
	case ISCSI_IWARP_SCTP:
	case ISCSI_INFINIBAND:
	default:
		pr_err("Unsupported network_transport: %d\n",
				np->np_network_transport);
		return -EINVAL;
	}

	np->np_ip_proto = IPPROTO_TCP;
	np->np_sock_type = SOCK_STREAM;

	ret = sock_create(sockaddr->ss_family, np->np_sock_type,
			np->np_ip_proto, &sock);
	if (ret < 0) {
@@ -853,7 +904,6 @@ int iscsi_target_setup_login_socket(
	}

	return 0;

fail:
	np->np_socket = NULL;
	if (sock)
@@ -861,21 +911,170 @@ fail:
	return ret;
}

int iscsi_target_setup_login_socket(
	struct iscsi_np *np,
	struct __kernel_sockaddr_storage *sockaddr)
{
	struct iscsit_transport *t;
	int rc;

	t = iscsit_get_transport(np->np_network_transport);
	if (!t)
		return -EINVAL;

	rc = t->iscsit_setup_np(np, sockaddr);
	if (rc < 0) {
		iscsit_put_transport(t);
		return rc;
	}

	np->np_transport = t;
	printk("Set np->np_transport to %p -> %s\n", np->np_transport,
				np->np_transport->name);
	return 0;
}

int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
{
	struct socket *new_sock, *sock = np->np_socket;
	struct sockaddr_in sock_in;
	struct sockaddr_in6 sock_in6;
	int rc, err;

	rc = kernel_accept(sock, &new_sock, 0);
	if (rc < 0)
		return rc;

	conn->sock = new_sock;
	conn->login_family = np->np_sockaddr.ss_family;
	printk("iSCSI/TCP: Setup conn->sock from new_sock: %p\n", new_sock);

	if (np->np_sockaddr.ss_family == AF_INET6) {
		memset(&sock_in6, 0, sizeof(struct sockaddr_in6));

		rc = conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in6, &err, 1);
		if (!rc) {
			snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
				&sock_in6.sin6_addr.in6_u);
			conn->login_port = ntohs(sock_in6.sin6_port);
		}

		rc = conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in6, &err, 0);
		if (!rc) {
			snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
				&sock_in6.sin6_addr.in6_u);
			conn->local_port = ntohs(sock_in6.sin6_port);
		}
	} else {
		memset(&sock_in, 0, sizeof(struct sockaddr_in));

		rc = conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in, &err, 1);
		if (!rc) {
			sprintf(conn->login_ip, "%pI4",
					&sock_in.sin_addr.s_addr);
			conn->login_port = ntohs(sock_in.sin_port);
		}

		rc = conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in, &err, 0);
		if (!rc) {
			sprintf(conn->local_ip, "%pI4",
					&sock_in.sin_addr.s_addr);
			conn->local_port = ntohs(sock_in.sin_port);
		}
	}

	return 0;
}

int iscsit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
{
	struct iscsi_login_req *login_req;
	u32 padding = 0, payload_length;

	if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
		return -1;

	login_req = (struct iscsi_login_req *)login->req;
	payload_length	= ntoh24(login_req->dlength);
	padding = ((-payload_length) & 3);

	pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
		" CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
		login_req->flags, login_req->itt, login_req->cmdsn,
		login_req->exp_statsn, login_req->cid, payload_length);
	/*
	 * Setup the initial iscsi_login values from the leading
	 * login request PDU.
	 */
	if (login->first_request) {
		login_req = (struct iscsi_login_req *)login->req;
		login->leading_connection = (!login_req->tsih) ? 1 : 0;
		login->current_stage	=
			(login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
		login->version_min	= login_req->min_version;
		login->version_max	= login_req->max_version;
		memcpy(login->isid, login_req->isid, 6);
		login->cmd_sn		= be32_to_cpu(login_req->cmdsn);
		login->init_task_tag	= login_req->itt;
		login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
		login->cid		= be16_to_cpu(login_req->cid);
		login->tsih		= be16_to_cpu(login_req->tsih);
	}

	if (iscsi_target_check_login_request(conn, login) < 0)
		return -1;

	memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
	if (iscsi_login_rx_data(conn, login->req_buf,
				payload_length + padding) < 0)
		return -1;

	return 0;
}

int iscsit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
			u32 length)
{
	if (iscsi_login_tx_data(conn, login->rsp, login->rsp_buf, length) < 0)
		return -1;

	return 0;
}

static int
iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t)
{
	int rc;

	if (!t->owner) {
		conn->conn_transport = t;
		return 0;
	}

	rc = try_module_get(t->owner);
	if (!rc) {
		pr_err("try_module_get() failed for %s\n", t->name);
		return -EINVAL;
	}

	conn->conn_transport = t;
	return 0;
}

static int __iscsi_target_login_thread(struct iscsi_np *np)
{
	u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0;
	int err, ret = 0, stop;
	u8 *buffer, zero_tsih = 0;
	int ret = 0, rc, stop;
	struct iscsi_conn *conn = NULL;
	struct iscsi_login *login;
	struct iscsi_portal_group *tpg = NULL;
	struct socket *new_sock, *sock;
	struct kvec iov;
	struct iscsi_login_req *pdu;
	struct sockaddr_in sock_in;
	struct sockaddr_in6 sock_in6;

	flush_signals(current);
	sock = np->np_socket;

	spin_lock_bh(&np->np_thread_lock);
	if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
@@ -886,70 +1085,71 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
	}
	spin_unlock_bh(&np->np_thread_lock);

	if (kernel_accept(sock, &new_sock, 0) < 0) {
		spin_lock_bh(&np->np_thread_lock);
		if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
			spin_unlock_bh(&np->np_thread_lock);
			complete(&np->np_restart_comp);
			/* Get another socket */
			return 1;
		}
		spin_unlock_bh(&np->np_thread_lock);
		goto out;
	}
	iscsi_start_login_thread_timer(np);

	conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
	if (!conn) {
		pr_err("Could not allocate memory for"
			" new connection\n");
		sock_release(new_sock);
		/* Get another socket */
		return 1;
	}

	pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
	conn->conn_state = TARG_CONN_STATE_FREE;
	conn->sock = new_sock;

	pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
	conn->conn_state = TARG_CONN_STATE_XPT_UP;
	if (iscsit_conn_set_transport(conn, np->np_transport) < 0) {
		kfree(conn);
		return 1;
	}

	/*
	 * Allocate conn->conn_ops early as a failure calling
	 * iscsit_tx_login_rsp() below will call tx_data().
	 */
	conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
	if (!conn->conn_ops) {
		pr_err("Unable to allocate memory for"
			" struct iscsi_conn_ops.\n");
		goto new_sess_out;
	rc = np->np_transport->iscsit_accept_np(np, conn);
	if (rc == -ENOSYS) {
		complete(&np->np_restart_comp);
		iscsit_put_transport(conn->conn_transport);
		kfree(conn);
		conn = NULL;
		goto exit;
	} else if (rc < 0) {
		spin_lock_bh(&np->np_thread_lock);
		if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
			spin_unlock_bh(&np->np_thread_lock);
			complete(&np->np_restart_comp);
			if (ret == -ENODEV) {
				iscsit_put_transport(conn->conn_transport);
				kfree(conn);
				conn = NULL;
				goto out;
			}
			/* Get another socket */
			return 1;
		}
		spin_unlock_bh(&np->np_thread_lock);
		iscsit_put_transport(conn->conn_transport);
		kfree(conn);
		conn = NULL;
		goto out;
	}
	/*
	 * Perform the remaining iSCSI connection initialization items..
	 */
	if (iscsi_login_init_conn(conn) < 0)
		goto new_sess_out;

	memset(buffer, 0, ISCSI_HDR_LEN);
	memset(&iov, 0, sizeof(struct kvec));
	iov.iov_base	= buffer;
	iov.iov_len	= ISCSI_HDR_LEN;

	if (rx_data(conn, &iov, 1, ISCSI_HDR_LEN) <= 0) {
		pr_err("rx_data() returned an error.\n");
	login = iscsi_login_init_conn(conn);
	if (!login) {
		goto new_sess_out;
	}

	iscsi_opcode = (buffer[0] & ISCSI_OPCODE_MASK);
	if (!(iscsi_opcode & ISCSI_OP_LOGIN)) {
		pr_err("First opcode is not login request,"
			" failing login request.\n");
	iscsi_start_login_thread_timer(np);

	pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
	conn->conn_state = TARG_CONN_STATE_XPT_UP;
	/*
	 * This will process the first login request + payload..
	 */
	rc = np->np_transport->iscsit_get_login_rx(conn, login);
	if (rc == 1)
		return 1;
	else if (rc < 0)
		goto new_sess_out;
	}

	buffer = &login->req[0];
	pdu = (struct iscsi_login_req *)buffer;

	/*
	 * Used by iscsit_tx_login_rsp() for Login Resonses PDUs
	 * when Status-Class != 0.
@@ -967,60 +1167,10 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
	}
	spin_unlock_bh(&np->np_thread_lock);

	if (np->np_sockaddr.ss_family == AF_INET6) {
		memset(&sock_in6, 0, sizeof(struct sockaddr_in6));

		if (conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in6, &err, 1) < 0) {
			pr_err("sock_ops->getname() failed.\n");
			iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
					ISCSI_LOGIN_STATUS_TARGET_ERROR);
			goto new_sess_out;
		}
		snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
				&sock_in6.sin6_addr.in6_u);
		conn->login_port = ntohs(sock_in6.sin6_port);

		if (conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in6, &err, 0) < 0) {
			pr_err("sock_ops->getname() failed.\n");
			iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
					ISCSI_LOGIN_STATUS_TARGET_ERROR);
			goto new_sess_out;
		}
		snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
				&sock_in6.sin6_addr.in6_u);
		conn->local_port = ntohs(sock_in6.sin6_port);

	} else {
		memset(&sock_in, 0, sizeof(struct sockaddr_in));

		if (conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in, &err, 1) < 0) {
			pr_err("sock_ops->getname() failed.\n");
			iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
					ISCSI_LOGIN_STATUS_TARGET_ERROR);
			goto new_sess_out;
		}
		sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr);
		conn->login_port = ntohs(sock_in.sin_port);

		if (conn->sock->ops->getname(conn->sock,
				(struct sockaddr *)&sock_in, &err, 0) < 0) {
			pr_err("sock_ops->getname() failed.\n");
			iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
					ISCSI_LOGIN_STATUS_TARGET_ERROR);
			goto new_sess_out;
		}
		sprintf(conn->local_ip, "%pI4", &sock_in.sin_addr.s_addr);
		conn->local_port = ntohs(sock_in.sin_port);
	}

	conn->network_transport = np->np_network_transport;

	pr_debug("Received iSCSI login request from %s on %s Network"
			" Portal %s:%hu\n", conn->login_ip,
		(conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP",
		" Portal %s:%hu\n", conn->login_ip, np->np_transport->name,
		conn->local_ip, conn->local_port);

	pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
@@ -1050,13 +1200,17 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
		if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0)
			goto new_sess_out;
	}

	/*
	 * This will process the first login request, and call
	 * iscsi_target_locate_portal(), and return a valid struct iscsi_login.
	 * SessionType: Discovery
	 *
	 * 	Locates Default Portal
	 *
	 * SessionType: Normal
	 *
	 * 	Locates Target Portal from NP -> Target IQN
	 */
	login = iscsi_target_init_negotiation(np, conn, buffer);
	if (!login) {
	rc = iscsi_target_locate_portal(np, conn, login);
	if (rc < 0) {
		tpg = conn->tpg;
		goto new_sess_out;
	}
@@ -1068,16 +1222,12 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
	}

	if (zero_tsih) {
		if (iscsi_login_zero_tsih_s2(conn) < 0) {
			iscsi_target_nego_release(login, conn);
		if (iscsi_login_zero_tsih_s2(conn) < 0)
			goto new_sess_out;
		}
	} else {
		if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) {
			iscsi_target_nego_release(login, conn);
		if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0)
			goto old_sess_out;
	}
	}

	if (iscsi_target_start_negotiation(login, conn) < 0)
		goto new_sess_out;
@@ -1153,8 +1303,18 @@ old_sess_out:
		iscsi_release_param_list(conn->param_list);
		conn->param_list = NULL;
	}
	if (conn->sock)
	iscsi_target_nego_release(conn);

	if (conn->sock) {
		sock_release(conn->sock);
		conn->sock = NULL;
	}

	if (conn->conn_transport->iscsit_free_conn)
		conn->conn_transport->iscsit_free_conn(conn);

	iscsit_put_transport(conn->conn_transport);

	kfree(conn);

	if (tpg) {
@@ -1172,11 +1332,13 @@ out:
	/* Wait for another socket.. */
	if (!stop)
		return 1;

exit:
	iscsi_stop_login_thread_timer(np);
	spin_lock_bh(&np->np_thread_lock);
	np->np_thread_state = ISCSI_NP_THREAD_EXIT;
	np->np_thread = NULL;
	spin_unlock_bh(&np->np_thread_lock);

	return 0;
}

+6 −0
Original line number Diff line number Diff line
@@ -4,8 +4,14 @@
extern int iscsi_login_setup_crypto(struct iscsi_conn *);
extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *);
extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32);
extern int iscsit_setup_np(struct iscsi_np *,
				struct __kernel_sockaddr_storage *);
extern int iscsi_target_setup_login_socket(struct iscsi_np *,
				struct __kernel_sockaddr_storage *);
extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *);
extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
extern int iscsi_target_login_thread(void *);
extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *);

+19 −148
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>

#include "iscsi_target_core.h"
#include "iscsi_target_parameters.h"
@@ -169,7 +170,7 @@ static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn)
	kfree(conn->auth_protocol);
}

static int iscsi_target_check_login_request(
int iscsi_target_check_login_request(
	struct iscsi_conn *conn,
	struct iscsi_login *login)
{
@@ -352,10 +353,7 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log

	padding = ((-login->rsp_length) & 3);

	if (iscsi_login_tx_data(
			conn,
			login->rsp,
			login->rsp_buf,
	if (conn->conn_transport->iscsit_put_login_tx(conn, login,
					login->rsp_length + padding) < 0)
		return -1;

@@ -368,72 +366,12 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
	return 0;
}

static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
{
	u32 padding = 0, payload_length;
	struct iscsi_login_req *login_req;

	if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
		return -1;

	login_req = (struct iscsi_login_req *) login->req;
	payload_length			= ntoh24(login_req->dlength);

	pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
		" CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
		 login_req->flags, login_req->itt, login_req->cmdsn,
		 login_req->exp_statsn, login_req->cid, payload_length);

	if (iscsi_target_check_login_request(conn, login) < 0)
		return -1;

	padding = ((-payload_length) & 3);
	memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);

	if (iscsi_login_rx_data(
			conn,
			login->req_buf,
			payload_length + padding) < 0)
		return -1;

	return 0;
}

static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
{
	if (iscsi_target_do_tx_login_io(conn, login) < 0)
		return -1;

	if (iscsi_target_do_rx_login_io(conn, login) < 0)
		return -1;

	return 0;
}

static int iscsi_target_get_initial_payload(
	struct iscsi_conn *conn,
	struct iscsi_login *login)
{
	u32 padding = 0, payload_length;
	struct iscsi_login_req *login_req;

	login_req = (struct iscsi_login_req *) login->req;
	payload_length = ntoh24(login_req->dlength);

	pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
		" CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
		login_req->flags, login_req->itt, login_req->cmdsn,
		login_req->exp_statsn, payload_length);

	if (iscsi_target_check_login_request(conn, login) < 0)
		return -1;

	padding = ((-payload_length) & 3);

	if (iscsi_login_rx_data(
			conn,
			login->req_buf,
			payload_length + padding) < 0)
	if (conn->conn_transport->iscsit_get_login_rx(conn, login) < 0)
		return -1;

	return 0;
@@ -693,6 +631,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo
				return -1;
			if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
				login->tsih = conn->sess->tsih;
				login->login_complete = 1;
				if (iscsi_target_do_tx_login_io(conn,
						login) < 0)
					return -1;
@@ -736,7 +675,7 @@ static void iscsi_initiatorname_tolower(
/*
 * Processes the first Login Request..
 */
static int iscsi_target_locate_portal(
int iscsi_target_locate_portal(
	struct iscsi_np *np,
	struct iscsi_conn *conn,
	struct iscsi_login *login)
@@ -798,6 +737,8 @@ static int iscsi_target_locate_portal(
		start += strlen(key) + strlen(value) + 2;
	}

	printk("i_buf: %s, s_buf: %s, t_buf: %s\n", i_buf, s_buf, t_buf);

	/*
	 * See 5.3.  Login Phase.
	 */
@@ -956,100 +897,30 @@ out:
	return ret;
}

struct iscsi_login *iscsi_target_init_negotiation(
	struct iscsi_np *np,
	struct iscsi_conn *conn,
	char *login_pdu)
{
	struct iscsi_login *login;

	login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
	if (!login) {
		pr_err("Unable to allocate memory for struct iscsi_login.\n");
		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
				ISCSI_LOGIN_STATUS_NO_RESOURCES);
		return NULL;
	}

	login->req = kmemdup(login_pdu, ISCSI_HDR_LEN, GFP_KERNEL);
	if (!login->req) {
		pr_err("Unable to allocate memory for Login Request.\n");
		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
				ISCSI_LOGIN_STATUS_NO_RESOURCES);
		goto out;
	}

	login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
	if (!login->req_buf) {
		pr_err("Unable to allocate memory for response buffer.\n");
		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
				ISCSI_LOGIN_STATUS_NO_RESOURCES);
		goto out;
	}
	/*
	 * SessionType: Discovery
	 *
	 *	Locates Default Portal
	 *
	 * SessionType: Normal
	 *
	 *	Locates Target Portal from NP -> Target IQN
	 */
	if (iscsi_target_locate_portal(np, conn, login) < 0) {
		goto out;
	}

	return login;
out:
	kfree(login->req);
	kfree(login->req_buf);
	kfree(login);

	return NULL;
}

int iscsi_target_start_negotiation(
	struct iscsi_login *login,
	struct iscsi_conn *conn)
{
	int ret = -1;

	login->rsp = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
	if (!login->rsp) {
		pr_err("Unable to allocate memory for"
				" Login Response.\n");
		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
				ISCSI_LOGIN_STATUS_NO_RESOURCES);
		ret = -1;
		goto out;
	}

	login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
	if (!login->rsp_buf) {
		pr_err("Unable to allocate memory for"
			" request buffer.\n");
		iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
				ISCSI_LOGIN_STATUS_NO_RESOURCES);
		ret = -1;
		goto out;
	}
	int ret;

	ret = iscsi_target_do_login(conn, login);
out:
	if (ret != 0)
		iscsi_remove_failed_auth_entry(conn);

	iscsi_target_nego_release(login, conn);
	iscsi_target_nego_release(conn);
	return ret;
}

void iscsi_target_nego_release(
	struct iscsi_login *login,
	struct iscsi_conn *conn)
void iscsi_target_nego_release(struct iscsi_conn *conn)
{
	kfree(login->req);
	kfree(login->rsp);
	struct iscsi_login *login = conn->conn_login;

	if (!login)
		return;

	kfree(login->req_buf);
	kfree(login->rsp_buf);
	kfree(login);

	conn->conn_login = NULL;
}
Loading