From cead6beb89256ae7145b65fbe8e8a5fedba4a47c Mon Sep 17 00:00:00 2001 From: Qing Zhang Date: Fri, 23 Oct 2026 19:29:28 +0800 Subject: [PATCH] nvmet: protect nvmet_ports_list with nvmet_config_sem Readers of nvmet_ports_list (e.g. nvmet_subsys_disc_changed()) hold nvmet_config_sem and assert it via lockdep. The writers -- nvmet_ports_make() and nvmet_port_release() -- do not take the lock; they rely on the parent directory's VFS inode lock for serialization, which is an implementation detail of configfs and not a guaranteed contract. Align the writers with the lock the readers already require. Also move list_add() in nvmet_ports_make() to after the port is fully initialized: the old position published the port on the global list before INIT_LIST_HEAD(&port->subsystems), so a concurrent reader could traverse uninitialized list heads. flush_workqueue() in nvmet_port_release() stays outside the semaphore to avoid a lock dependency on nvmet_wq. Fixes: b662a078576e ("nvmet: enable Discovery Controller AENs") Reviewed-by: Maurizio Lombardi Signed-off-by: Qing Zhang Signed-off-by: Keith Busch --- drivers/nvme/target/configfs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index 2b085327320e..7cd88d6bfd61 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -2103,7 +2103,9 @@ static void nvmet_port_release(struct config_item *item) /* Let inflight controllers teardown complete */ flush_workqueue(nvmet_wq); + down_write(&nvmet_config_sem); list_del(&port->global_entry); + up_write(&nvmet_config_sem); key_put(port->keyring); kfree(port); @@ -2164,8 +2166,6 @@ static struct config_group *nvmet_ports_make(struct config_group *group, port->ana_state[i] = NVME_ANA_INACCESSIBLE; } - list_add(&port->global_entry, &nvmet_ports_list); - INIT_LIST_HEAD(&port->entry); INIT_LIST_HEAD(&port->subsystems); INIT_LIST_HEAD(&port->referrals); @@ -2199,6 +2199,10 @@ static struct config_group *nvmet_ports_make(struct config_group *group, configfs_add_default_group(&port->ana_default_group.group, &port->ana_groups_group); + down_write(&nvmet_config_sem); + list_add(&port->global_entry, &nvmet_ports_list); + up_write(&nvmet_config_sem); + return &port->group; }