Re: [PATCH v3 03/17] scsi: iscsi: stop queueing during ep_disconnect

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 4/15/21 7:04 PM, Mike Christie wrote:
> During ep_disconnect we have been doing iscsi_suspend_tx/queue to block
> new IO but every driver except cxgbi and iscsi_tcp can still get IO from
> __iscsi_conn_send_pdu if we haven't called iscsi_conn_failure before
> ep_disconnect. This could happen if we were terminating the session, and
> the logout timedout before it was even sent to libiscsi.
> 
> This patch fixes the issue by adding a helper which reverses the bind_conn
> call that allows new IO to be queued. Drivers implementing ep_disconnect
> can use this to make sure new IO is not queued to them when handling the
> disconnect.
> 
> Signed-off-by: Mike Christie <michael.christie@xxxxxxxxxx>
> ---
>  drivers/infiniband/ulp/iser/iscsi_iser.c |  1 +
>  drivers/scsi/be2iscsi/be_main.c          |  1 +
>  drivers/scsi/bnx2i/bnx2i_iscsi.c         |  1 +
>  drivers/scsi/cxgbi/cxgb3i/cxgb3i.c       |  1 +
>  drivers/scsi/cxgbi/cxgb4i/cxgb4i.c       |  1 +
>  drivers/scsi/libiscsi.c                  | 61 +++++++++++++++++++++---
>  drivers/scsi/qedi/qedi_iscsi.c           |  1 +
>  drivers/scsi/qla4xxx/ql4_os.c            |  1 +
>  drivers/scsi/scsi_transport_iscsi.c      |  3 ++
>  include/scsi/libiscsi.h                  |  1 +
>  include/scsi/scsi_transport_iscsi.h      |  1 +
>  11 files changed, 67 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
> index 8fcaa1136f2c..6baebcb6d14d 100644
> --- a/drivers/infiniband/ulp/iser/iscsi_iser.c
> +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
> @@ -1002,6 +1002,7 @@ static struct iscsi_transport iscsi_iser_transport = {
>  	/* connection management */
>  	.create_conn            = iscsi_iser_conn_create,
>  	.bind_conn              = iscsi_iser_conn_bind,
> +	.unbind_conn		= iscsi_conn_unbind,
>  	.destroy_conn           = iscsi_conn_teardown,
>  	.attr_is_visible	= iser_attr_is_visible,
>  	.set_param              = iscsi_iser_set_param,
> diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
> index 90fcddb76f46..e9658a67d9da 100644
> --- a/drivers/scsi/be2iscsi/be_main.c
> +++ b/drivers/scsi/be2iscsi/be_main.c
> @@ -5809,6 +5809,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
>  	.destroy_session = beiscsi_session_destroy,
>  	.create_conn = beiscsi_conn_create,
>  	.bind_conn = beiscsi_conn_bind,
> +	.unbind_conn = iscsi_conn_unbind,
>  	.destroy_conn = iscsi_conn_teardown,
>  	.attr_is_visible = beiscsi_attr_is_visible,
>  	.set_iface_param = beiscsi_iface_set_param,
> diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
> index 1e6d8f62ea3c..b6c1da46d582 100644
> --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
> +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
> @@ -2276,6 +2276,7 @@ struct iscsi_transport bnx2i_iscsi_transport = {
>  	.destroy_session	= bnx2i_session_destroy,
>  	.create_conn		= bnx2i_conn_create,
>  	.bind_conn		= bnx2i_conn_bind,
> +	.unbind_conn		= iscsi_conn_unbind,
>  	.destroy_conn		= bnx2i_conn_destroy,
>  	.attr_is_visible	= bnx2i_attr_is_visible,
>  	.set_param		= iscsi_set_param,
> diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
> index 37d99357120f..edcd3fab6973 100644
> --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
> +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
> @@ -117,6 +117,7 @@ static struct iscsi_transport cxgb3i_iscsi_transport = {
>  	/* connection management */
>  	.create_conn	= cxgbi_create_conn,
>  	.bind_conn	= cxgbi_bind_conn,
> +	.unbind_conn	= iscsi_conn_unbind,
>  	.destroy_conn	= iscsi_tcp_conn_teardown,
>  	.start_conn	= iscsi_conn_start,
>  	.stop_conn	= iscsi_conn_stop,
> diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
> index 2c3491528d42..efb3e2b3398e 100644
> --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
> +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
> @@ -134,6 +134,7 @@ static struct iscsi_transport cxgb4i_iscsi_transport = {
>  	/* connection management */
>  	.create_conn	= cxgbi_create_conn,
>  	.bind_conn		= cxgbi_bind_conn,
> +	.unbind_conn	= iscsi_conn_unbind,
>  	.destroy_conn	= iscsi_tcp_conn_teardown,
>  	.start_conn		= iscsi_conn_start,
>  	.stop_conn		= iscsi_conn_stop,
> diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
> index aa5ceaffc697..ce3898fdb10f 100644
> --- a/drivers/scsi/libiscsi.c
> +++ b/drivers/scsi/libiscsi.c
> @@ -1387,22 +1387,28 @@ void iscsi_session_failure(struct iscsi_session *session,
>  }
>  EXPORT_SYMBOL_GPL(iscsi_session_failure);
>  
> -void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
> +static void iscsi_set_conn_failed(struct iscsi_conn *conn)
>  {
>  	struct iscsi_session *session = conn->session;
>  
> -	spin_lock_bh(&session->frwd_lock);
> -	if (session->state == ISCSI_STATE_FAILED) {
> -		spin_unlock_bh(&session->frwd_lock);
> +	if (session->state == ISCSI_STATE_FAILED)
>  		return;
> -	}
>  
>  	if (conn->stop_stage == 0)
>  		session->state = ISCSI_STATE_FAILED;
> -	spin_unlock_bh(&session->frwd_lock);
>  
>  	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
>  	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
> +}
> +
> +void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
> +{
> +	struct iscsi_session *session = conn->session;
> +
> +	spin_lock_bh(&session->frwd_lock);
> +	iscsi_set_conn_failed(conn);
> +	spin_unlock_bh(&session->frwd_lock);
> +
>  	iscsi_conn_error_event(conn->cls_conn, err);
>  }
>  EXPORT_SYMBOL_GPL(iscsi_conn_failure);
> @@ -2220,6 +2226,49 @@ static void iscsi_check_transport_timeouts(struct timer_list *t)
>  	spin_unlock(&session->frwd_lock);
>  }
>  
> +/*
> + * iscsi_conn_unbind - prevent queueing to conn.
> + * @conn: iscsi conn ep is bound to.
> + *
> + * This must be called by drivers implementing the ep_disconnect callout.
> + * It disables queueing to the connection from libiscsi in preparation for
> + * an ep_disconnect call.
> + */
> +void iscsi_conn_unbind(struct iscsi_cls_conn *cls_conn)
> +{
> +	struct iscsi_session *session;
> +	struct iscsi_conn *conn;
> +
> +	if (!cls_conn)
> +		return;
> +
> +	conn = cls_conn->dd_data;
> +	session = conn->session;
> +	/*
> +	 * Wait for iscsi_eh calls to exit. We don't wait for the tmf to
> +	 * complete or timeout. The caller just wants to know what's running
> +	 * is everything that needs to be cleaned up, and no cmds will be
> +	 * queued.
> +	 */
> +	mutex_lock(&session->eh_mutex);
> +
> +	iscsi_suspend_queue(conn);
> +	iscsi_suspend_tx(conn);
> +
> +	spin_lock_bh(&session->frwd_lock);
> +	/*
> +	 * if logout timed out before userspace could even send a PDU the
> +	 * state might still be in ISCSI_STATE_LOGGED_IN and allowing new cmds
> +	 * and TMFs.
> +	 */
> +	if (session->state == ISCSI_STATE_LOGGED_IN)
> +		iscsi_set_conn_failed(conn);
> +
> +	spin_unlock_bh(&session->frwd_lock);
> +	mutex_unlock(&session->eh_mutex);
> +}
> +EXPORT_SYMBOL_GPL(iscsi_conn_unbind);
> +
>  static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
>  				      struct iscsi_tm *hdr)
>  {
> diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
> index 08c05403cd72..ef16537c523c 100644
> --- a/drivers/scsi/qedi/qedi_iscsi.c
> +++ b/drivers/scsi/qedi/qedi_iscsi.c
> @@ -1401,6 +1401,7 @@ struct iscsi_transport qedi_iscsi_transport = {
>  	.destroy_session = qedi_session_destroy,
>  	.create_conn = qedi_conn_create,
>  	.bind_conn = qedi_conn_bind,
> +	.unbind_conn = iscsi_conn_unbind,
>  	.start_conn = qedi_conn_start,
>  	.stop_conn = iscsi_conn_stop,
>  	.destroy_conn = qedi_conn_destroy,
> diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
> index 7bd9a4a04ad5..ff663cb330c2 100644
> --- a/drivers/scsi/qla4xxx/ql4_os.c
> +++ b/drivers/scsi/qla4xxx/ql4_os.c
> @@ -259,6 +259,7 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
>  	.start_conn             = qla4xxx_conn_start,
>  	.create_conn            = qla4xxx_conn_create,
>  	.bind_conn              = qla4xxx_conn_bind,
> +	.unbind_conn		= iscsi_conn_unbind,
>  	.stop_conn              = iscsi_conn_stop,
>  	.destroy_conn           = qla4xxx_conn_destroy,
>  	.set_param              = iscsi_set_param,
> diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
> index 441f0152193f..833114c8e197 100644
> --- a/drivers/scsi/scsi_transport_iscsi.c
> +++ b/drivers/scsi/scsi_transport_iscsi.c
> @@ -2981,6 +2981,8 @@ static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
>  		conn->ep = NULL;
>  		mutex_unlock(&conn->ep_mutex);
>  		conn->state = ISCSI_CONN_FAILED;
> +
> +		transport->unbind_conn(conn);
>  	}
>  
>  	transport->ep_disconnect(ep);
> @@ -4656,6 +4658,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
>  	int err;
>  
>  	BUG_ON(!tt);
> +	WARN_ON(tt->ep_disconnect && !tt->unbind_conn);
>  
>  	priv = iscsi_if_transport_lookup(tt);
>  	if (priv)
> diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
> index 8c6d358a8abc..ec6d508e7a4a 100644
> --- a/include/scsi/libiscsi.h
> +++ b/include/scsi/libiscsi.h
> @@ -431,6 +431,7 @@ extern int iscsi_conn_start(struct iscsi_cls_conn *);
>  extern void iscsi_conn_stop(struct iscsi_cls_conn *, int);
>  extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *,
>  			   int);
> +extern void iscsi_conn_unbind(struct iscsi_cls_conn *cls_conn);
>  extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err);
>  extern void iscsi_session_failure(struct iscsi_session *session,
>  				  enum iscsi_err err);
> diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
> index fc5a39839b4b..afc61a23628d 100644
> --- a/include/scsi/scsi_transport_iscsi.h
> +++ b/include/scsi/scsi_transport_iscsi.h
> @@ -82,6 +82,7 @@ struct iscsi_transport {
>  	void (*destroy_session) (struct iscsi_cls_session *session);
>  	struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
>  				uint32_t cid);
> +	void (*unbind_conn) (struct iscsi_cls_conn *conn);
>  	int (*bind_conn) (struct iscsi_cls_session *session,
>  			  struct iscsi_cls_conn *cls_conn,
>  			  uint64_t transport_eph, int is_leading);
> 

Reviewed-by: Lee Duncan <lduncan@xxxxxxxx>




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux