Skip to content

Commit 6a81533

Browse files
Arun Easimartinkpetersen
authored andcommitted
scsi: qla2xxx: Fix kernel crash after disconnecting NVMe devices
BUG: unable to handle kernel NULL pointer dereference at (null) IP: [<ffffffffc050d10c>] qla_nvme_unregister_remote_port+0x6c/0xf0 [qla2xxx] PGD 800000084cf41067 PUD 84d288067 PMD 0 Oops: 0000 [#1] SMP Call Trace: [<ffffffff98abcfdf>] process_one_work+0x17f/0x440 [<ffffffff98abdca6>] worker_thread+0x126/0x3c0 [<ffffffff98abdb80>] ? manage_workers.isra.26+0x2a0/0x2a0 [<ffffffff98ac4f81>] kthread+0xd1/0xe0 [<ffffffff98ac4eb0>] ? insert_kthread_work+0x40/0x40 [<ffffffff9918ad37>] ret_from_fork_nospec_begin+0x21/0x21 [<ffffffff98ac4eb0>] ? insert_kthread_work+0x40/0x40 RIP [<ffffffffc050d10c>] qla_nvme_unregister_remote_port+0x6c/0xf0 [qla2xxx] The crash is due to a bad entry in the nvme_rport_list. This list is not protected, and when a remoteport_delete callback is called, driver traverses the list and crashes. Actually, the list could be removed and driver could traverse the main fcport list instead. Fix does exactly that. Signed-off-by: Arun Easi <[email protected]> Signed-off-by: Himanshu Madhani <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent f5258d6 commit 6a81533

File tree

4 files changed

+10
-30
lines changed

4 files changed

+10
-30
lines changed

drivers/scsi/qla2xxx/qla_def.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4376,7 +4376,6 @@ typedef struct scsi_qla_host {
43764376

43774377
struct nvme_fc_local_port *nvme_local_port;
43784378
struct completion nvme_del_done;
4379-
struct list_head nvme_rport_list;
43804379

43814380
uint16_t fcoe_vlan_id;
43824381
uint16_t fcoe_fcf_idx;

drivers/scsi/qla2xxx/qla_nvme.c

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
7474

7575
rport = fcport->nvme_remote_port->private;
7676
rport->fcport = fcport;
77-
list_add_tail(&rport->list, &vha->nvme_rport_list);
7877

7978
fcport->nvme_flag |= NVME_FLAG_REGISTERED;
8079
return 0;
@@ -542,19 +541,12 @@ static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport)
542541
static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
543542
{
544543
fc_port_t *fcport;
545-
struct qla_nvme_rport *qla_rport = rport->private, *trport;
544+
struct qla_nvme_rport *qla_rport = rport->private;
546545

547546
fcport = qla_rport->fcport;
548547
fcport->nvme_remote_port = NULL;
549548
fcport->nvme_flag &= ~NVME_FLAG_REGISTERED;
550549

551-
list_for_each_entry_safe(qla_rport, trport,
552-
&fcport->vha->nvme_rport_list, list) {
553-
if (qla_rport->fcport == fcport) {
554-
list_del(&qla_rport->list);
555-
break;
556-
}
557-
}
558550
complete(&fcport->nvme_del_done);
559551

560552
if (!test_bit(UNLOADING, &fcport->vha->dpc_flags)) {
@@ -590,31 +582,22 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work)
590582
{
591583
struct fc_port *fcport = container_of(work, struct fc_port,
592584
nvme_del_work);
593-
struct qla_nvme_rport *qla_rport, *trport;
585+
int ret;
594586

595587
if (!IS_ENABLED(CONFIG_NVME_FC))
596588
return;
597589

598590
ql_log(ql_log_warn, NULL, 0x2112,
599591
"%s: unregister remoteport on %p\n",__func__, fcport);
600592

601-
list_for_each_entry_safe(qla_rport, trport,
602-
&fcport->vha->nvme_rport_list, list) {
603-
if (qla_rport->fcport == fcport) {
604-
ql_log(ql_log_info, fcport->vha, 0x2113,
605-
"%s: fcport=%p\n", __func__, fcport);
606-
nvme_fc_set_remoteport_devloss
607-
(fcport->nvme_remote_port, 0);
608-
init_completion(&fcport->nvme_del_done);
609-
if (nvme_fc_unregister_remoteport
610-
(fcport->nvme_remote_port))
611-
ql_log(ql_log_info, fcport->vha, 0x2114,
612-
"%s: Failed to unregister nvme_remote_port\n",
613-
__func__);
614-
wait_for_completion(&fcport->nvme_del_done);
615-
break;
616-
}
617-
}
593+
nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0);
594+
init_completion(&fcport->nvme_del_done);
595+
ret = nvme_fc_unregister_remoteport(fcport->nvme_remote_port);
596+
if (ret)
597+
ql_log(ql_log_info, fcport->vha, 0x2114,
598+
"%s: Failed to unregister nvme_remote_port (%d)\n",
599+
__func__, ret);
600+
wait_for_completion(&fcport->nvme_del_done);
618601
}
619602

620603
void qla_nvme_delete(struct scsi_qla_host *vha)

drivers/scsi/qla2xxx/qla_nvme.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ struct nvme_private {
3737
};
3838

3939
struct qla_nvme_rport {
40-
struct list_head list;
4140
struct fc_port *fcport;
4241
};
4342

drivers/scsi/qla2xxx/qla_os.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4789,7 +4789,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
47894789
INIT_LIST_HEAD(&vha->plogi_ack_list);
47904790
INIT_LIST_HEAD(&vha->qp_list);
47914791
INIT_LIST_HEAD(&vha->gnl.fcports);
4792-
INIT_LIST_HEAD(&vha->nvme_rport_list);
47934792
INIT_LIST_HEAD(&vha->gpnid_list);
47944793
INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn);
47954794

0 commit comments

Comments
 (0)