Message ID | 20220517222448.25612-5-michael.christie@oracle.com |
---|---|
State | Superseded |
Headers | show |
Series | iscsi fixes, perf improvements and cleanups | expand |
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 --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,
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(-)