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

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

iscsi-target: Prepare login code for multi-plexing support



This patch prepares the iscsi-target login code for multi-plexing
support.  This includes:

 - Adding iscsi_tpg_np->tpg_np_kref + iscsit_login_kref_put() for
   handling callback of iscsi_tpg_np->tpg_np_comp
 - Adding kref_put() in iscsit_deaccess_np()
 - Adding kref_put() and wait_for_completion() in
   iscsit_reset_np_thread()
 - Refactor login failure path release logic into
   iscsi_target_login_sess_out()
 - Update __iscsi_target_login_thread() to handle
   iscsi_post_login_handler() asynchronous completion
 - Add shutdown parameter for iscsit_clear_tpg_np_login_thread*()

v3 changes:
 - Convert iscsi_portal_group->np_login_lock to ->np_login_sem
 - Add LOGIN_FLAGS definitions

v2 changes:
 - Remove duplicate call to iscsi_post_login_handler() in
   __iscsi_target_login_thread()
 - Drop unused iscsi_np->np_login_tpg

Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent dfecf611
Loading
Loading
Loading
Loading
+29 −26
Original line number Original line Diff line number Diff line
@@ -220,11 +220,6 @@ int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
		spin_unlock_bh(&np->np_thread_lock);
		spin_unlock_bh(&np->np_thread_lock);
		return -1;
		return -1;
	}
	}
	if (np->np_login_tpg) {
		pr_err("np->np_login_tpg() is not NULL!\n");
		spin_unlock_bh(&np->np_thread_lock);
		return -1;
	}
	spin_unlock_bh(&np->np_thread_lock);
	spin_unlock_bh(&np->np_thread_lock);
	/*
	/*
	 * Determine if the portal group is accepting storage traffic.
	 * Determine if the portal group is accepting storage traffic.
@@ -239,26 +234,38 @@ int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
	/*
	/*
	 * Here we serialize access across the TIQN+TPG Tuple.
	 * Here we serialize access across the TIQN+TPG Tuple.
	 */
	 */
	ret = mutex_lock_interruptible(&tpg->np_login_lock);
	ret = down_interruptible(&tpg->np_login_sem);
	if ((ret != 0) || signal_pending(current))
	if ((ret != 0) || signal_pending(current))
		return -1;
		return -1;


	spin_lock_bh(&np->np_thread_lock);
	spin_lock_bh(&tpg->tpg_state_lock);
	np->np_login_tpg = tpg;
	if (tpg->tpg_state != TPG_STATE_ACTIVE) {
	spin_unlock_bh(&np->np_thread_lock);
		spin_unlock_bh(&tpg->tpg_state_lock);
		up(&tpg->np_login_sem);
		return -1;
	}
	spin_unlock_bh(&tpg->tpg_state_lock);


	return 0;
	return 0;
}
}


int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
void iscsit_login_kref_put(struct kref *kref)
{
	struct iscsi_tpg_np *tpg_np = container_of(kref,
				struct iscsi_tpg_np, tpg_np_kref);

	complete(&tpg_np->tpg_np_comp);
}

int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg,
		       struct iscsi_tpg_np *tpg_np)
{
{
	struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
	struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;


	spin_lock_bh(&np->np_thread_lock);
	up(&tpg->np_login_sem);
	np->np_login_tpg = NULL;
	spin_unlock_bh(&np->np_thread_lock);


	mutex_unlock(&tpg->np_login_lock);
	if (tpg_np)
		kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);


	if (tiqn)
	if (tiqn)
		iscsit_put_tiqn_for_login(tiqn);
		iscsit_put_tiqn_for_login(tiqn);
@@ -410,20 +417,10 @@ struct iscsi_np *iscsit_add_np(
int iscsit_reset_np_thread(
int iscsit_reset_np_thread(
	struct iscsi_np *np,
	struct iscsi_np *np,
	struct iscsi_tpg_np *tpg_np,
	struct iscsi_tpg_np *tpg_np,
	struct iscsi_portal_group *tpg)
	struct iscsi_portal_group *tpg,
	bool shutdown)
{
{
	spin_lock_bh(&np->np_thread_lock);
	spin_lock_bh(&np->np_thread_lock);
	if (tpg && tpg_np) {
		/*
		 * The reset operation need only be performed when the
		 * passed struct iscsi_portal_group has a login in progress
		 * to one of the network portals.
		 */
		if (tpg_np->tpg_np->np_login_tpg != tpg) {
			spin_unlock_bh(&np->np_thread_lock);
			return 0;
		}
	}
	if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) {
	if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) {
		spin_unlock_bh(&np->np_thread_lock);
		spin_unlock_bh(&np->np_thread_lock);
		return 0;
		return 0;
@@ -438,6 +435,12 @@ int iscsit_reset_np_thread(
	}
	}
	spin_unlock_bh(&np->np_thread_lock);
	spin_unlock_bh(&np->np_thread_lock);


	if (tpg_np && shutdown) {
		kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);

		wait_for_completion(&tpg_np->tpg_np_comp);
	}

	return 0;
	return 0;
}
}


+4 −2
Original line number Original line Diff line number Diff line
@@ -7,13 +7,15 @@ extern void iscsit_put_tiqn_for_login(struct iscsi_tiqn *);
extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *);
extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *);
extern void iscsit_del_tiqn(struct iscsi_tiqn *);
extern void iscsit_del_tiqn(struct iscsi_tiqn *);
extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *);
extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *);
extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *);
extern void iscsit_login_kref_put(struct kref *);
extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *,
				struct iscsi_tpg_np *);
extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *,
extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *,
				struct iscsi_np *, int);
				struct iscsi_np *, int);
extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,
extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,
				char *, int);
				char *, int);
extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
				struct iscsi_portal_group *);
				struct iscsi_portal_group *, bool);
extern int iscsit_del_np(struct iscsi_np *);
extern int iscsit_del_np(struct iscsi_np *);
extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *);
extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *);
extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
+13 −2
Original line number Original line Diff line number Diff line
@@ -554,6 +554,13 @@ struct iscsi_conn {
	struct completion	rx_half_close_comp;
	struct completion	rx_half_close_comp;
	/* socket used by this connection */
	/* socket used by this connection */
	struct socket		*sock;
	struct socket		*sock;
	void			(*orig_data_ready)(struct sock *, int);
#define LOGIN_FLAGS_READ_ACTIVE		1
#define LOGIN_FLAGS_CLOSED		2
#define LOGIN_FLAGS_READY		4
	unsigned long		login_flags;
	struct delayed_work	login_work;
	struct iscsi_login	*login;
	struct timer_list	nopin_timer;
	struct timer_list	nopin_timer;
	struct timer_list	nopin_response_timer;
	struct timer_list	nopin_response_timer;
	struct timer_list	transport_timer;
	struct timer_list	transport_timer;
@@ -584,6 +591,7 @@ struct iscsi_conn {
	void			*context;
	void			*context;
	struct iscsi_login_thread_s *login_thread;
	struct iscsi_login_thread_s *login_thread;
	struct iscsi_portal_group *tpg;
	struct iscsi_portal_group *tpg;
	struct iscsi_tpg_np	*tpg_np;
	/* Pointer to parent session */
	/* Pointer to parent session */
	struct iscsi_session	*sess;
	struct iscsi_session	*sess;
	/* Pointer to thread_set in use for this conn's threads */
	/* Pointer to thread_set in use for this conn's threads */
@@ -682,6 +690,7 @@ struct iscsi_login {
	u8 version_max;
	u8 version_max;
	u8 login_complete;
	u8 login_complete;
	u8 login_failed;
	u8 login_failed;
	bool zero_tsih;
	char isid[6];
	char isid[6];
	u32 cmd_sn;
	u32 cmd_sn;
	itt_t init_task_tag;
	itt_t init_task_tag;
@@ -694,6 +703,7 @@ struct iscsi_login {
	char *req_buf;
	char *req_buf;
	char *rsp_buf;
	char *rsp_buf;
	struct iscsi_conn *conn;
	struct iscsi_conn *conn;
	struct iscsi_np *np;
} ____cacheline_aligned;
} ____cacheline_aligned;


struct iscsi_node_attrib {
struct iscsi_node_attrib {
@@ -773,7 +783,6 @@ struct iscsi_np {
	struct __kernel_sockaddr_storage np_sockaddr;
	struct __kernel_sockaddr_storage np_sockaddr;
	struct task_struct	*np_thread;
	struct task_struct	*np_thread;
	struct timer_list	np_login_timer;
	struct timer_list	np_login_timer;
	struct iscsi_portal_group *np_login_tpg;
	void			*np_context;
	void			*np_context;
	struct iscsit_transport *np_transport;
	struct iscsit_transport *np_transport;
	struct list_head	np_list;
	struct list_head	np_list;
@@ -788,6 +797,8 @@ struct iscsi_tpg_np {
	struct list_head	tpg_np_parent_list;
	struct list_head	tpg_np_parent_list;
	struct se_tpg_np	se_tpg_np;
	struct se_tpg_np	se_tpg_np;
	spinlock_t		tpg_np_parent_lock;
	spinlock_t		tpg_np_parent_lock;
	struct completion	tpg_np_comp;
	struct kref		tpg_np_kref;
};
};


struct iscsi_portal_group {
struct iscsi_portal_group {
@@ -809,7 +820,7 @@ struct iscsi_portal_group {
	spinlock_t		tpg_state_lock;
	spinlock_t		tpg_state_lock;
	struct se_portal_group tpg_se_tpg;
	struct se_portal_group tpg_se_tpg;
	struct mutex		tpg_access_lock;
	struct mutex		tpg_access_lock;
	struct mutex		np_login_lock;
	struct semaphore	np_login_sem;
	struct iscsi_tpg_attrib	tpg_attrib;
	struct iscsi_tpg_attrib	tpg_attrib;
	struct iscsi_node_auth	tpg_demo_auth;
	struct iscsi_node_auth	tpg_demo_auth;
	/* Pointer to default list of iSCSI parameters for TPG */
	/* Pointer to default list of iSCSI parameters for TPG */
+93 −69
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
		pr_err("Unable to allocate memory for struct iscsi_login.\n");
		pr_err("Unable to allocate memory for struct iscsi_login.\n");
		return NULL;
		return NULL;
	}
	}
	conn->login = login;
	login->conn = conn;
	login->conn = conn;
	login->first_request = 1;
	login->first_request = 1;


@@ -684,7 +685,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
		iscsit_start_nopin_timer(conn);
		iscsit_start_nopin_timer(conn);
}
}


static int iscsi_post_login_handler(
int iscsi_post_login_handler(
	struct iscsi_np *np,
	struct iscsi_np *np,
	struct iscsi_conn *conn,
	struct iscsi_conn *conn,
	u8 zero_tsih)
	u8 zero_tsih)
@@ -1124,6 +1125,77 @@ iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t)
	return 0;
	return 0;
}
}


void iscsi_target_login_sess_out(struct iscsi_conn *conn,
		struct iscsi_np *np, bool zero_tsih, bool new_sess)
{
	if (new_sess == false)
		goto old_sess_out;

	pr_err("iSCSI Login negotiation failed.\n");
	iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
				   ISCSI_LOGIN_STATUS_INIT_ERR);
	if (!zero_tsih || !conn->sess)
		goto old_sess_out;
	if (conn->sess->se_sess)
		transport_free_session(conn->sess->se_sess);
	if (conn->sess->session_index != 0) {
		spin_lock_bh(&sess_idr_lock);
		idr_remove(&sess_idr, conn->sess->session_index);
		spin_unlock_bh(&sess_idr_lock);
	}
	kfree(conn->sess->sess_ops);
	kfree(conn->sess);

old_sess_out:
	iscsi_stop_login_thread_timer(np);
	/*
	 * If login negotiation fails check if the Time2Retain timer
	 * needs to be restarted.
	 */
	if (!zero_tsih && conn->sess) {
		spin_lock_bh(&conn->sess->conn_lock);
		if (conn->sess->session_state == TARG_SESS_STATE_FAILED) {
			struct se_portal_group *se_tpg =
					&ISCSI_TPG_C(conn)->tpg_se_tpg;

			atomic_set(&conn->sess->session_continuation, 0);
			spin_unlock_bh(&conn->sess->conn_lock);
			spin_lock_bh(&se_tpg->session_lock);
			iscsit_start_time2retain_handler(conn->sess);
			spin_unlock_bh(&se_tpg->session_lock);
		} else
			spin_unlock_bh(&conn->sess->conn_lock);
		iscsit_dec_session_usage_count(conn->sess);
	}

	if (!IS_ERR(conn->conn_rx_hash.tfm))
		crypto_free_hash(conn->conn_rx_hash.tfm);
	if (!IS_ERR(conn->conn_tx_hash.tfm))
		crypto_free_hash(conn->conn_tx_hash.tfm);

	if (conn->conn_cpumask)
		free_cpumask_var(conn->conn_cpumask);

	kfree(conn->conn_ops);

	if (conn->param_list) {
		iscsi_release_param_list(conn->param_list);
		conn->param_list = NULL;
	}
	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);
}

static int __iscsi_target_login_thread(struct iscsi_np *np)
static int __iscsi_target_login_thread(struct iscsi_np *np)
{
{
	u8 *buffer, zero_tsih = 0;
	u8 *buffer, zero_tsih = 0;
@@ -1132,6 +1204,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
	struct iscsi_login *login;
	struct iscsi_login *login;
	struct iscsi_portal_group *tpg = NULL;
	struct iscsi_portal_group *tpg = NULL;
	struct iscsi_login_req *pdu;
	struct iscsi_login_req *pdu;
	struct iscsi_tpg_np *tpg_np;
	bool new_sess = false;


	flush_signals(current);
	flush_signals(current);


@@ -1273,6 +1347,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
		tpg = conn->tpg;
		tpg = conn->tpg;
		goto new_sess_out;
		goto new_sess_out;
	}
	}
	login->zero_tsih = zero_tsih;


	tpg = conn->tpg;
	tpg = conn->tpg;
	if (!tpg) {
	if (!tpg) {
@@ -1288,7 +1363,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
			goto old_sess_out;
			goto old_sess_out;
	}
	}


	if (iscsi_target_start_negotiation(login, conn) < 0)
	ret = iscsi_target_start_negotiation(login, conn);
	if (ret < 0)
		goto new_sess_out;
		goto new_sess_out;


	if (!conn->sess) {
	if (!conn->sess) {
@@ -1301,84 +1377,32 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
	if (signal_pending(current))
	if (signal_pending(current))
		goto new_sess_out;
		goto new_sess_out;


	ret = iscsi_post_login_handler(np, conn, zero_tsih);
	if (ret == 1) {
		tpg_np = conn->tpg_np;


		ret = iscsi_post_login_handler(np, conn, zero_tsih);
		if (ret < 0)
		if (ret < 0)
			goto new_sess_out;
			goto new_sess_out;


	iscsit_deaccess_np(np, tpg);
		iscsit_deaccess_np(np, tpg, tpg_np);
	}

	tpg = NULL;
	tpg = NULL;
	tpg_np = NULL;
	/* Get another socket */
	/* Get another socket */
	return 1;
	return 1;


new_sess_out:
new_sess_out:
	pr_err("iSCSI Login negotiation failed.\n");
	new_sess = true;
	iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
				  ISCSI_LOGIN_STATUS_INIT_ERR);
	if (!zero_tsih || !conn->sess)
		goto old_sess_out;
	if (conn->sess->se_sess)
		transport_free_session(conn->sess->se_sess);
	if (conn->sess->session_index != 0) {
		spin_lock_bh(&sess_idr_lock);
		idr_remove(&sess_idr, conn->sess->session_index);
		spin_unlock_bh(&sess_idr_lock);
	}
	kfree(conn->sess->sess_ops);
	kfree(conn->sess);
old_sess_out:
old_sess_out:
	iscsi_stop_login_thread_timer(np);
	tpg_np = conn->tpg_np;
	/*
	iscsi_target_login_sess_out(conn, np, zero_tsih, new_sess);
	 * If login negotiation fails check if the Time2Retain timer
	new_sess = false;
	 * needs to be restarted.
	 */
	if (!zero_tsih && conn->sess) {
		spin_lock_bh(&conn->sess->conn_lock);
		if (conn->sess->session_state == TARG_SESS_STATE_FAILED) {
			struct se_portal_group *se_tpg =
					&ISCSI_TPG_C(conn)->tpg_se_tpg;

			atomic_set(&conn->sess->session_continuation, 0);
			spin_unlock_bh(&conn->sess->conn_lock);
			spin_lock_bh(&se_tpg->session_lock);
			iscsit_start_time2retain_handler(conn->sess);
			spin_unlock_bh(&se_tpg->session_lock);
		} else
			spin_unlock_bh(&conn->sess->conn_lock);
		iscsit_dec_session_usage_count(conn->sess);
	}

	if (!IS_ERR(conn->conn_rx_hash.tfm))
		crypto_free_hash(conn->conn_rx_hash.tfm);
	if (!IS_ERR(conn->conn_tx_hash.tfm))
		crypto_free_hash(conn->conn_tx_hash.tfm);

	if (conn->conn_cpumask)
		free_cpumask_var(conn->conn_cpumask);

	kfree(conn->conn_ops);

	if (conn->param_list) {
		iscsi_release_param_list(conn->param_list);
		conn->param_list = NULL;
	}
	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) {
	if (tpg) {
		iscsit_deaccess_np(np, tpg);
		iscsit_deaccess_np(np, tpg, tpg_np);
		tpg = NULL;
		tpg = NULL;
		tpg_np = NULL;
	}
	}


out:
out:
+3 −0
Original line number Original line Diff line number Diff line
@@ -12,6 +12,9 @@ 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_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
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 void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *,
				bool, bool);
extern int iscsi_target_login_thread(void *);
extern int iscsi_target_login_thread(void *);
extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *);
extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *);


Loading