scsi: qla2xxx: Fix crash when I/O abort times out
authorArun Easi <aeasi@marvell.com>
Tue, 29 Nov 2022 09:26:34 +0000 (01:26 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 31 Dec 2022 12:33:11 +0000 (13:33 +0100)
commit 68ad83188d782b2ecef2e41ac245d27e0710fe8e upstream.

While performing CPU hotplug, a crash with the following stack was seen:

Call Trace:
     qla24xx_process_response_queue+0x42a/0x970 [qla2xxx]
     qla2x00_start_nvme_mq+0x3a2/0x4b0 [qla2xxx]
     qla_nvme_post_cmd+0x166/0x240 [qla2xxx]
     nvme_fc_start_fcp_op.part.0+0x119/0x2e0 [nvme_fc]
     blk_mq_dispatch_rq_list+0x17b/0x610
     __blk_mq_sched_dispatch_requests+0xb0/0x140
     blk_mq_sched_dispatch_requests+0x30/0x60
     __blk_mq_run_hw_queue+0x35/0x90
     __blk_mq_delay_run_hw_queue+0x161/0x180
     blk_execute_rq+0xbe/0x160
     __nvme_submit_sync_cmd+0x16f/0x220 [nvme_core]
     nvmf_connect_admin_queue+0x11a/0x170 [nvme_fabrics]
     nvme_fc_create_association.cold+0x50/0x3dc [nvme_fc]
     nvme_fc_connect_ctrl_work+0x19/0x30 [nvme_fc]
     process_one_work+0x1e8/0x3c0

On abort timeout, completion was called without checking if the I/O was
already completed.

Verify that I/O and abort request are indeed outstanding before attempting
completion.

Fixes: 71c80b75ce8f ("scsi: qla2xxx: Do command completion on abort timeout")
Reported-by: Marco Patalano <mpatalan@redhat.com>
Tested-by: Marco Patalano <mpatalan@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Arun Easi <aeasi@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Link: https://lore.kernel.org/r/20221129092634.15347-1-njavali@marvell.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/scsi/qla2xxx/qla_init.c

index 6319935..432f47f 100644 (file)
@@ -110,6 +110,7 @@ static void qla24xx_abort_iocb_timeout(void *data)
        struct qla_qpair *qpair = sp->qpair;
        u32 handle;
        unsigned long flags;
+       int sp_found = 0, cmdsp_found = 0;
 
        if (sp->cmd_sp)
                ql_dbg(ql_dbg_async, sp->vha, 0x507c,
@@ -124,18 +125,21 @@ static void qla24xx_abort_iocb_timeout(void *data)
        spin_lock_irqsave(qpair->qp_lock_ptr, flags);
        for (handle = 1; handle < qpair->req->num_outstanding_cmds; handle++) {
                if (sp->cmd_sp && (qpair->req->outstanding_cmds[handle] ==
-                   sp->cmd_sp))
+                   sp->cmd_sp)) {
                        qpair->req->outstanding_cmds[handle] = NULL;
+                       cmdsp_found = 1;
+               }
 
                /* removing the abort */
                if (qpair->req->outstanding_cmds[handle] == sp) {
                        qpair->req->outstanding_cmds[handle] = NULL;
+                       sp_found = 1;
                        break;
                }
        }
        spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
 
-       if (sp->cmd_sp) {
+       if (cmdsp_found && sp->cmd_sp) {
                /*
                 * This done function should take care of
                 * original command ref: INIT
@@ -143,8 +147,10 @@ static void qla24xx_abort_iocb_timeout(void *data)
                sp->cmd_sp->done(sp->cmd_sp, QLA_OS_TIMER_EXPIRED);
        }
 
-       abt->u.abt.comp_status = cpu_to_le16(CS_TIMEOUT);
-       sp->done(sp, QLA_OS_TIMER_EXPIRED);
+       if (sp_found) {
+               abt->u.abt.comp_status = cpu_to_le16(CS_TIMEOUT);
+               sp->done(sp, QLA_OS_TIMER_EXPIRED);
+       }
 }
 
 static void qla24xx_abort_sp_done(srb_t *sp, int res)