scsi: iscsi: Fix session removal on shutdown
authorMike Christie <michael.christie@oracle.com>
Thu, 16 Jun 2022 22:27:38 +0000 (17:27 -0500)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 22 Jun 2022 01:14:54 +0000 (21:14 -0400)
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 commit d1f2ce77638d ("scsi:
qedi: Fix host removal with running sessions") which made qedi use the
common session removal function that waits on userspace instead of rolling
its own kernel based removal.

Link: https://lore.kernel.org/r/20220616222738.5722-7-michael.christie@oracle.com
Fixes: d1f2ce77638d ("scsi: qedi: Fix host removal with running sessions")
Tested-by: Nilesh Javali <njavali@marvell.com>
Reviewed-by: Lee Duncan <lduncan@suse.com>
Reviewed-by: Nilesh Javali <njavali@marvell.com>
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/cxgbi/libcxgbi.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/libiscsi.c
drivers/scsi/qedi/qedi_main.c
include/scsi/libiscsi.h

index 321949a570ed6fb2d2c94de4d556ded09f083879..620ae5b2d80dc0faae8054aa50574c8bd18ad365 100644 (file)
@@ -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;
index 3bb0adefbe06fa647a461b6360ef52bc56fd02f1..02026476c39c9a39d74634143215ecf88e1afac9 100644 (file)
@@ -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 */
index 15fbd09baa943a6caf1651ceddd336b5a11b5649..a3c800e04a2e81bea64d6ba373d1a6b3281526da 100644 (file)
@@ -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);
index 4365d52c6430e79db085e175e724c5d6eb34822f..32abdf0fa9aab89846343679bce642916a72fdbd 100644 (file)
@@ -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);
                }
index 9fee70d6434a8e6ac669079d8fce63fb412d6165..52c6f70d60ec4fb9e363c4db9907c0e5966a0ca5 100644 (file)
@@ -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);
 }
 
index 8d78559ae94a2b9aefb5e84911bfbf489b40dc42..3894decf8fbf771d0b051402832c431a00a383c4 100644 (file)
@@ -2832,11 +2832,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;
@@ -2845,7 +2846,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))
index deebe62e2b419379d9404277835cedca3b37d285..cecfb2cb4c7beb87cc61d8519c20be53753fa2c9 100644 (file)
@@ -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 @@ remove_host:
 #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:
index c0703cd20a9939da8ce514f20f9f1487f67ddb0d..9758a4a9923f570723c1c763948b8f598ffe14aa 100644 (file)
@@ -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,