scsi: qla2xxx: Fix unintialized List head crash
authorQuinn Tran <quinn.tran@cavium.com>
Wed, 18 Jul 2018 21:29:51 +0000 (14:29 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 20 Jul 2018 02:02:33 +0000 (22:02 -0400)
In case of IOCB Queue full or system where memory is low and driver
receives large number of RSCN storm, the stale sp pointer can stay on
gpnid_list resulting in page_fault.

This patch fixes this issue by initializing the sp->elem list head and
removing sp->elem before memory is freed.

Following stack trace is seen

 9 [ffff987b37d1bc60] page_fault at ffffffffad516768 [exception RIP: qla24xx_async_gpnid+496]
10 [ffff987b37d1bd10] qla24xx_async_gpnid at ffffffffc039866d [qla2xxx]
11 [ffff987b37d1bd80] qla2x00_do_work at ffffffffc036169c [qla2xxx]
12 [ffff987b37d1be38] qla2x00_do_dpc_all_vps at ffffffffc03adfed [qla2xxx]
13 [ffff987b37d1be78] qla2x00_do_dpc at ffffffffc036458a [qla2xxx]
14 [ffff987b37d1bec8] kthread at ffffffffacebae31

Fixes: 2d73ac6102d9 ("scsi: qla2xxx: Serialize GPNID for multiple RSCN")
Cc: <stable@vger.kernel.org> # v4.17+
Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_inline.h

index 2c35b0b2baa07f27211140fb0a7ea48b4cf8a7f4..7a3744006419589232322520594e635bdd247d36 100644 (file)
@@ -3708,6 +3708,10 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id)
        return rval;
 
 done_free_sp:
+       spin_lock_irqsave(&vha->hw->vport_slock, flags);
+       list_del(&sp->elem);
+       spin_unlock_irqrestore(&vha->hw->vport_slock, flags);
+
        if (sp->u.iocb_cmd.u.ctarg.req) {
                dma_free_coherent(&vha->hw->pdev->dev,
                        sizeof(struct ct_sns_pkt),
index 37ae0f6d8ae5743a182cc9fb963cbc868ddd925b..59fd5a9dfeb8703f437685fa7b4221419b42319e 100644 (file)
@@ -222,6 +222,8 @@ qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag)
        sp->fcport = fcport;
        sp->iocbs = 1;
        sp->vha = qpair->vha;
+       INIT_LIST_HEAD(&sp->elem);
+
 done:
        if (!sp)
                QLA_QPAIR_MARK_NOT_BUSY(qpair);