Skip to content

Commit 4c73cbd

Browse files
jsmart-ghChristoph Hellwig
authored andcommitted
nvme-fc: fix module unloads while lports still pending
Current code allows the module to be unloaded even if there are pending data structures, such as localports and controllers on the localports, that have yet to hit their reference counting to remove them. Fix by having exit entrypoint explicitly delete every controller, which in turn will remove references on the remoteports and localports causing them to be deleted as well. The exit entrypoint, after initiating the deletes, will wait for the last localport to be deleted before continuing. Signed-off-by: James Smart <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 37c1521 commit 4c73cbd

File tree

1 file changed

+48
-3
lines changed
  • drivers/nvme/host

1 file changed

+48
-3
lines changed

drivers/nvme/host/fc.c

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ static DEFINE_IDA(nvme_fc_ctrl_cnt);
204204

205205
static struct workqueue_struct *nvme_fc_wq;
206206

207+
static bool nvme_fc_waiting_to_unload;
208+
static DECLARE_COMPLETION(nvme_fc_unload_proceed);
209+
207210
/*
208211
* These items are short-term. They will eventually be moved into
209212
* a generic FC class. See comments in module init.
@@ -229,6 +232,8 @@ nvme_fc_free_lport(struct kref *ref)
229232
/* remove from transport list */
230233
spin_lock_irqsave(&nvme_fc_lock, flags);
231234
list_del(&lport->port_list);
235+
if (nvme_fc_waiting_to_unload && list_empty(&nvme_fc_lport_list))
236+
complete(&nvme_fc_unload_proceed);
232237
spin_unlock_irqrestore(&nvme_fc_lock, flags);
233238

234239
ida_simple_remove(&nvme_fc_local_port_cnt, lport->localport.port_num);
@@ -3456,11 +3461,51 @@ static int __init nvme_fc_init_module(void)
34563461
return ret;
34573462
}
34583463

3464+
static void
3465+
nvme_fc_delete_controllers(struct nvme_fc_rport *rport)
3466+
{
3467+
struct nvme_fc_ctrl *ctrl;
3468+
3469+
spin_lock(&rport->lock);
3470+
list_for_each_entry(ctrl, &rport->ctrl_list, ctrl_list) {
3471+
dev_warn(ctrl->ctrl.device,
3472+
"NVME-FC{%d}: transport unloading: deleting ctrl\n",
3473+
ctrl->cnum);
3474+
nvme_delete_ctrl(&ctrl->ctrl);
3475+
}
3476+
spin_unlock(&rport->lock);
3477+
}
3478+
3479+
static void
3480+
nvme_fc_cleanup_for_unload(void)
3481+
{
3482+
struct nvme_fc_lport *lport;
3483+
struct nvme_fc_rport *rport;
3484+
3485+
list_for_each_entry(lport, &nvme_fc_lport_list, port_list) {
3486+
list_for_each_entry(rport, &lport->endp_list, endp_list) {
3487+
nvme_fc_delete_controllers(rport);
3488+
}
3489+
}
3490+
}
3491+
34593492
static void __exit nvme_fc_exit_module(void)
34603493
{
3461-
/* sanity check - all lports should be removed */
3462-
if (!list_empty(&nvme_fc_lport_list))
3463-
pr_warn("%s: localport list not empty\n", __func__);
3494+
unsigned long flags;
3495+
bool need_cleanup = false;
3496+
3497+
spin_lock_irqsave(&nvme_fc_lock, flags);
3498+
nvme_fc_waiting_to_unload = true;
3499+
if (!list_empty(&nvme_fc_lport_list)) {
3500+
need_cleanup = true;
3501+
nvme_fc_cleanup_for_unload();
3502+
}
3503+
spin_unlock_irqrestore(&nvme_fc_lock, flags);
3504+
if (need_cleanup) {
3505+
pr_info("%s: waiting for ctlr deletes\n", __func__);
3506+
wait_for_completion(&nvme_fc_unload_proceed);
3507+
pr_info("%s: ctrl deletes complete\n", __func__);
3508+
}
34643509

34653510
nvmf_unregister_transport(&nvme_fc_transport);
34663511

0 commit comments

Comments
 (0)