diff mbox series

[04/13] scsi: iscsi: Fix session removal on shutdown

Message ID 20220517222448.25612-5-michael.christie@oracle.com
State Superseded
Headers show
Series iscsi fixes, perf improvements and cleanups | expand

Commit Message

Mike Christie May 17, 2022, 10:24 p.m. UTC
When the system is shutting down iscsid is not running, so we will not get
a response to the ISCSI_ERR_INVALID_HOST error event. The system shutdown
will then hang waiting on userspace to remove the session. This has
libiscsi force the destruction of the session from the kernel when
iscsi_host_remove is called from a driver's shutdown callout.

This fixes a regression added in qedi boot with patch:

Commit: d1f2ce77638d ("scsi: qedi: Fix host removal with running
sessions")

where in that patch I had qedi use the common session removal function
that waits on userspace instead of rolling it's own kernel based removal.

Fixes: d1f2ce77638d ("scsi: qedi: Fix host removal with running sessions")
Signed-off-by: Mike Christie <michael.christie@oracle.com>
---
 drivers/infiniband/ulp/iser/iscsi_iser.c | 4 ++--
 drivers/scsi/be2iscsi/be_main.c          | 2 +-
 drivers/scsi/bnx2i/bnx2i_iscsi.c         | 2 +-
 drivers/scsi/cxgbi/libcxgbi.c            | 2 +-
 drivers/scsi/iscsi_tcp.c                 | 4 ++--
 drivers/scsi/libiscsi.c                  | 9 +++++++--
 drivers/scsi/qedi/qedi_main.c            | 9 ++++++---
 include/scsi/libiscsi.h                  | 2 +-
 8 files changed, 21 insertions(+), 13 deletions(-)

Comments

Lee Duncan May 18, 2022, 9:42 p.m. UTC | #1
On 5/17/22 15:24, Mike Christie wrote:
> When the system is shutting down iscsid is not running, so we will not get
> a response to the ISCSI_ERR_INVALID_HOST error event. The system shutdown
> will then hang waiting on userspace to remove the session. This has
> libiscsi force the destruction of the session from the kernel when
> iscsi_host_remove is called from a driver's shutdown callout.
> 
> This fixes a regression added in qedi boot with patch:
> 
> Commit: d1f2ce77638d ("scsi: qedi: Fix host removal with running
> sessions")
> 
> where in that patch I had qedi use the common session removal function
> that waits on userspace instead of rolling it's own kernel based removal.
> 
> Fixes: d1f2ce77638d ("scsi: qedi: Fix host removal with running sessions")
> Signed-off-by: Mike Christie <michael.christie@oracle.com>
> ---
>   drivers/infiniband/ulp/iser/iscsi_iser.c | 4 ++--
>   drivers/scsi/be2iscsi/be_main.c          | 2 +-
>   drivers/scsi/bnx2i/bnx2i_iscsi.c         | 2 +-
>   drivers/scsi/cxgbi/libcxgbi.c            | 2 +-
>   drivers/scsi/iscsi_tcp.c                 | 4 ++--
>   drivers/scsi/libiscsi.c                  | 9 +++++++--
>   drivers/scsi/qedi/qedi_main.c            | 9 ++++++---
>   include/scsi/libiscsi.h                  | 2 +-
>   8 files changed, 21 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
> index f8d0bab4424c..e36036b8f386 100644
> --- a/drivers/infiniband/ulp/iser/iscsi_iser.c
> +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
> @@ -568,7 +568,7 @@ static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
>   	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
>   
>   	iscsi_session_teardown(cls_session);
> -	iscsi_host_remove(shost);
> +	iscsi_host_remove(shost, false);
>   	iscsi_host_free(shost);
>   }
>   
> @@ -685,7 +685,7 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
>   	return cls_session;
>   
>   remove_host:
> -	iscsi_host_remove(shost);
> +	iscsi_host_remove(shost, false);
>   free_host:
>   	iscsi_host_free(shost);
>   	return NULL;
> diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
> index 3bb0adefbe06..02026476c39c 100644
> --- a/drivers/scsi/be2iscsi/be_main.c
> +++ b/drivers/scsi/be2iscsi/be_main.c
> @@ -5745,7 +5745,7 @@ static void beiscsi_remove(struct pci_dev *pcidev)
>   	cancel_work_sync(&phba->sess_work);
>   
>   	beiscsi_iface_destroy_default(phba);
> -	iscsi_host_remove(phba->shost);
> +	iscsi_host_remove(phba->shost, false);
>   	beiscsi_disable_port(phba, 1);
>   
>   	/* after cancelling boot_work */
> diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
> index 15fbd09baa94..a3c800e04a2e 100644
> --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
> +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
> @@ -909,7 +909,7 @@ void bnx2i_free_hba(struct bnx2i_hba *hba)
>   {
>   	struct Scsi_Host *shost = hba->shost;
>   
> -	iscsi_host_remove(shost);
> +	iscsi_host_remove(shost, false);
>   	INIT_LIST_HEAD(&hba->ep_ofld_list);
>   	INIT_LIST_HEAD(&hba->ep_active_list);
>   	INIT_LIST_HEAD(&hba->ep_destroy_list);
> diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
> index 4365d52c6430..32abdf0fa9aa 100644
> --- a/drivers/scsi/cxgbi/libcxgbi.c
> +++ b/drivers/scsi/cxgbi/libcxgbi.c
> @@ -328,7 +328,7 @@ void cxgbi_hbas_remove(struct cxgbi_device *cdev)
>   		chba = cdev->hbas[i];
>   		if (chba) {
>   			cdev->hbas[i] = NULL;
> -			iscsi_host_remove(chba->shost);
> +			iscsi_host_remove(chba->shost, false);
>   			pci_dev_put(cdev->pdev);
>   			iscsi_host_free(chba->shost);
>   		}
> diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
> index 9fee70d6434a..52c6f70d60ec 100644
> --- a/drivers/scsi/iscsi_tcp.c
> +++ b/drivers/scsi/iscsi_tcp.c
> @@ -898,7 +898,7 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
>   remove_session:
>   	iscsi_session_teardown(cls_session);
>   remove_host:
> -	iscsi_host_remove(shost);
> +	iscsi_host_remove(shost, false);
>   free_host:
>   	iscsi_host_free(shost);
>   	return NULL;
> @@ -915,7 +915,7 @@ static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
>   	iscsi_tcp_r2tpool_free(cls_session->dd_data);
>   	iscsi_session_teardown(cls_session);
>   
> -	iscsi_host_remove(shost);
> +	iscsi_host_remove(shost, false);
>   	iscsi_host_free(shost);
>   }
>   
> diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
> index 797abf4f5399..3ddb701cd29c 100644
> --- a/drivers/scsi/libiscsi.c
> +++ b/drivers/scsi/libiscsi.c
> @@ -2828,11 +2828,12 @@ static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session)
>   /**
>    * iscsi_host_remove - remove host and sessions
>    * @shost: scsi host
> + * @is_shutdown: true if called from a driver shutdown callout
>    *
>    * If there are any sessions left, this will initiate the removal and wait
>    * for the completion.
>    */
> -void iscsi_host_remove(struct Scsi_Host *shost)
> +void iscsi_host_remove(struct Scsi_Host *shost, bool is_shutdown)
>   {
>   	struct iscsi_host *ihost = shost_priv(shost);
>   	unsigned long flags;
> @@ -2841,7 +2842,11 @@ void iscsi_host_remove(struct Scsi_Host *shost)
>   	ihost->state = ISCSI_HOST_REMOVED;
>   	spin_unlock_irqrestore(&ihost->lock, flags);
>   
> -	iscsi_host_for_each_session(shost, iscsi_notify_host_removed);
> +	if (!is_shutdown)
> +		iscsi_host_for_each_session(shost, iscsi_notify_host_removed);
> +	else
> +		iscsi_host_for_each_session(shost, iscsi_force_destroy_session);
> +
>   	wait_event_interruptible(ihost->session_removal_wq,
>   				 ihost->num_sessions == 0);
>   	if (signal_pending(current))
> diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
> index deebe62e2b41..cecfb2cb4c7b 100644
> --- a/drivers/scsi/qedi/qedi_main.c
> +++ b/drivers/scsi/qedi/qedi_main.c
> @@ -2414,9 +2414,12 @@ static void __qedi_remove(struct pci_dev *pdev, int mode)
>   	int rval;
>   	u16 retry = 10;
>   
> -	if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) {
> -		iscsi_host_remove(qedi->shost);
> +	if (mode == QEDI_MODE_NORMAL)
> +		iscsi_host_remove(qedi->shost, false);
> +	else if (mode == QEDI_MODE_SHUTDOWN)
> +		iscsi_host_remove(qedi->shost, true);
>   
> +	if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) {
>   		if (qedi->tmf_thread) {
>   			destroy_workqueue(qedi->tmf_thread);
>   			qedi->tmf_thread = NULL;
> @@ -2791,7 +2794,7 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
>   #ifdef CONFIG_DEBUG_FS
>   	qedi_dbg_host_exit(&qedi->dbg_ctx);
>   #endif
> -	iscsi_host_remove(qedi->shost);
> +	iscsi_host_remove(qedi->shost, false);
>   stop_iscsi_func:
>   	qedi_ops->stop(qedi->cdev);
>   stop_slowpath:
> diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
> index d0a24779c52d..471422641ab3 100644
> --- a/include/scsi/libiscsi.h
> +++ b/include/scsi/libiscsi.h
> @@ -411,7 +411,7 @@ extern int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev);
>   extern struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
>   					  int dd_data_size,
>   					  bool xmit_can_sleep);
> -extern void iscsi_host_remove(struct Scsi_Host *shost);
> +extern void iscsi_host_remove(struct Scsi_Host *shost, bool is_shutdown);
>   extern void iscsi_host_free(struct Scsi_Host *shost);
>   extern int iscsi_target_alloc(struct scsi_target *starget);
>   extern int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,

Reviewed-by: Lee Duncan <lduncan@suse.com>
diff mbox series

Patch

diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index f8d0bab4424c..e36036b8f386 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -568,7 +568,7 @@  static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
 	struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
 
 	iscsi_session_teardown(cls_session);
-	iscsi_host_remove(shost);
+	iscsi_host_remove(shost, false);
 	iscsi_host_free(shost);
 }
 
@@ -685,7 +685,7 @@  iscsi_iser_session_create(struct iscsi_endpoint *ep,
 	return cls_session;
 
 remove_host:
-	iscsi_host_remove(shost);
+	iscsi_host_remove(shost, false);
 free_host:
 	iscsi_host_free(shost);
 	return NULL;
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 3bb0adefbe06..02026476c39c 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -5745,7 +5745,7 @@  static void beiscsi_remove(struct pci_dev *pcidev)
 	cancel_work_sync(&phba->sess_work);
 
 	beiscsi_iface_destroy_default(phba);
-	iscsi_host_remove(phba->shost);
+	iscsi_host_remove(phba->shost, false);
 	beiscsi_disable_port(phba, 1);
 
 	/* after cancelling boot_work */
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 15fbd09baa94..a3c800e04a2e 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -909,7 +909,7 @@  void bnx2i_free_hba(struct bnx2i_hba *hba)
 {
 	struct Scsi_Host *shost = hba->shost;
 
-	iscsi_host_remove(shost);
+	iscsi_host_remove(shost, false);
 	INIT_LIST_HEAD(&hba->ep_ofld_list);
 	INIT_LIST_HEAD(&hba->ep_active_list);
 	INIT_LIST_HEAD(&hba->ep_destroy_list);
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 4365d52c6430..32abdf0fa9aa 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -328,7 +328,7 @@  void cxgbi_hbas_remove(struct cxgbi_device *cdev)
 		chba = cdev->hbas[i];
 		if (chba) {
 			cdev->hbas[i] = NULL;
-			iscsi_host_remove(chba->shost);
+			iscsi_host_remove(chba->shost, false);
 			pci_dev_put(cdev->pdev);
 			iscsi_host_free(chba->shost);
 		}
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 9fee70d6434a..52c6f70d60ec 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -898,7 +898,7 @@  iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
 remove_session:
 	iscsi_session_teardown(cls_session);
 remove_host:
-	iscsi_host_remove(shost);
+	iscsi_host_remove(shost, false);
 free_host:
 	iscsi_host_free(shost);
 	return NULL;
@@ -915,7 +915,7 @@  static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session)
 	iscsi_tcp_r2tpool_free(cls_session->dd_data);
 	iscsi_session_teardown(cls_session);
 
-	iscsi_host_remove(shost);
+	iscsi_host_remove(shost, false);
 	iscsi_host_free(shost);
 }
 
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 797abf4f5399..3ddb701cd29c 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2828,11 +2828,12 @@  static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session)
 /**
  * iscsi_host_remove - remove host and sessions
  * @shost: scsi host
+ * @is_shutdown: true if called from a driver shutdown callout
  *
  * If there are any sessions left, this will initiate the removal and wait
  * for the completion.
  */
-void iscsi_host_remove(struct Scsi_Host *shost)
+void iscsi_host_remove(struct Scsi_Host *shost, bool is_shutdown)
 {
 	struct iscsi_host *ihost = shost_priv(shost);
 	unsigned long flags;
@@ -2841,7 +2842,11 @@  void iscsi_host_remove(struct Scsi_Host *shost)
 	ihost->state = ISCSI_HOST_REMOVED;
 	spin_unlock_irqrestore(&ihost->lock, flags);
 
-	iscsi_host_for_each_session(shost, iscsi_notify_host_removed);
+	if (!is_shutdown)
+		iscsi_host_for_each_session(shost, iscsi_notify_host_removed);
+	else
+		iscsi_host_for_each_session(shost, iscsi_force_destroy_session);
+
 	wait_event_interruptible(ihost->session_removal_wq,
 				 ihost->num_sessions == 0);
 	if (signal_pending(current))
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index deebe62e2b41..cecfb2cb4c7b 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -2414,9 +2414,12 @@  static void __qedi_remove(struct pci_dev *pdev, int mode)
 	int rval;
 	u16 retry = 10;
 
-	if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) {
-		iscsi_host_remove(qedi->shost);
+	if (mode == QEDI_MODE_NORMAL)
+		iscsi_host_remove(qedi->shost, false);
+	else if (mode == QEDI_MODE_SHUTDOWN)
+		iscsi_host_remove(qedi->shost, true);
 
+	if (mode == QEDI_MODE_NORMAL || mode == QEDI_MODE_SHUTDOWN) {
 		if (qedi->tmf_thread) {
 			destroy_workqueue(qedi->tmf_thread);
 			qedi->tmf_thread = NULL;
@@ -2791,7 +2794,7 @@  static int __qedi_probe(struct pci_dev *pdev, int mode)
 #ifdef CONFIG_DEBUG_FS
 	qedi_dbg_host_exit(&qedi->dbg_ctx);
 #endif
-	iscsi_host_remove(qedi->shost);
+	iscsi_host_remove(qedi->shost, false);
 stop_iscsi_func:
 	qedi_ops->stop(qedi->cdev);
 stop_slowpath:
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index d0a24779c52d..471422641ab3 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -411,7 +411,7 @@  extern int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev);
 extern struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
 					  int dd_data_size,
 					  bool xmit_can_sleep);
-extern void iscsi_host_remove(struct Scsi_Host *shost);
+extern void iscsi_host_remove(struct Scsi_Host *shost, bool is_shutdown);
 extern void iscsi_host_free(struct Scsi_Host *shost);
 extern int iscsi_target_alloc(struct scsi_target *starget);
 extern int iscsi_host_get_max_scsi_cmds(struct Scsi_Host *shost,