[PATCH v2 04/20] scsi: ibmvfc: defer NVMe local port registration out of atomic context
From: Tyrel Datwyler <tyreld@linux.ibm.com>
Date: 2026-09-19 01:33:23
Also in:
linux-scsi, lkml
Subsystem:
ibm power virtual fc device drivers, linux for powerpc (32-bit and 64-bit), scsi subsystem, the rest · Maintainers:
Tyrel Datwyler, Madhavan Srinivasan, "James E.J. Bottomley", "Martin K. Petersen", Linus Torvalds
ibmvfc_fabric_login_nvme_done() is invoked under vhost->host->host_lock
via the ibmvfc_locked_done() wrapper, which acquires the spinlock with
IRQs disabled before calling the MAD completion handler.
On the IBMVFC_MAD_SUCCESS path the handler called ibmvfc_nvme_register()
directly. That function calls nvme_fc_register_localport(), which
performs GFP_KERNEL memory allocations and may sleep — both illegal
inside a spinlock-held (atomic) context — resulting in a 'scheduling
while atomic' kernel panic during NVMe/FC fabric login.
Fix this by replacing the direct call with a new do_nvme_register flag
that mirrors the existing do_nvme_login pattern already used in the
driver. The flag is consumed in ibmvfc_do_work() under the
IBMVFC_HOST_ACTION_QUERY case, which runs in the kernel thread context
(ibmvfc_work) where sleeping allocations are safe. The lock is dropped
before calling ibmvfc_nvme_register() and re-acquired on return so the
rest of the QUERY case proceeds normally.
Fixes: 3831863f9f56 ("ibmvfc: register local nvme fc port after fabric login")
Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
---
drivers/scsi/ibmvscsi/ibmvfc-core.c | 12 +++++++++++-
drivers/scsi/ibmvscsi/ibmvfc.h | 1 +
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ibmvfc-core.c
index 6558ed3c67c4..728529155ded 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc-core.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c@@ -991,6 +991,7 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) vhost->using_channels = 0; vhost->do_scsi_login = 0; vhost->do_nvme_login = 0; + vhost->do_nvme_register = 0; spin_unlock(vhost->crq.q_lock); spin_unlock_irqrestore(&vhost->host->host_lock, flags);
@@ -1032,6 +1033,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) vhost->using_channels = 0; vhost->do_scsi_login = 0; vhost->do_nvme_login = 0; + vhost->do_nvme_register = 0; /* Clean out the queue */ memset(crq->msgs.crq, 0, PAGE_SIZE);
@@ -5243,7 +5245,7 @@ static void ibmvfc_fabric_login_nvme_done(struct ibmvfc_event *evt) switch (mad_status) { case IBMVFC_MAD_SUCCESS: fc_host_port_id(vhost->host) = be64_to_cpu(rsp->nport_id); - ibmvfc_nvme_register(vhost); + vhost->do_nvme_register = 1; ibmvfc_dbg(vhost, "NVMe fabric login succeeded\n"); break; case IBMVFC_MAD_FAILED:
@@ -6070,6 +6072,14 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) vhost->job_step(vhost); break; case IBMVFC_HOST_ACTION_QUERY: + if (vhost->do_nvme_register) { + vhost->do_nvme_register = 0; + spin_unlock_irqrestore(&vhost->host->host_lock, flags); + ibmvfc_nvme_register(vhost); + spin_lock_irqsave(&vhost->host->host_lock, flags); + if (vhost->action != IBMVFC_HOST_ACTION_QUERY) + break; + } list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) ibmvfc_init_tgt(tgt, ibmvfc_tgt_query_target); list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue)
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index ca80ceffe53a..df0775183d72 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h@@ -1005,6 +1005,7 @@ struct ibmvfc_host { unsigned int nvme_enabled:1; unsigned int do_scsi_login:1; unsigned int do_nvme_login:1; + unsigned int do_nvme_register:1; unsigned int aborting_passthru:1; unsigned int scan_complete:1; int scan_timeout;
--
2.55.0