From f6b512ffdbcad8014d0981a36eb49e1289969c0f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 10 Nov 2026 09:17:00 -0800 Subject: [PATCH 3/3] nvme: Pass the subsystem pointer to nvme_alloc_ns_head() Pass the struct nvme_subsystem pointer directly to nvme_alloc_ns_head(). Update the __must_hold() annotation to check &subsys->lock instead of &ns->ctrl->subsys->lock, and access subsys directly instead of through ctrl->subsys. Notice that nvme_subsystem::nsheads is guarded by &nvme_subsystem::lock. Observe that Clang lock context analysis cannot verify lock requirements when accessing nsheads through the nested pointer ns->ctrl->subsys. Enable the compiler to verify that &subsys->lock is held while modifying &subsys->nsheads by passing the subsystem pointer directly. Fixes: d1fdf49b5f7f ("nvme: add context annotations for nvme_subsystem::lock") Signed-off-by: Bart Van Assche --- drivers/nvme/host/core.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 98c39fef0646..c5ca25122f8e 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -4052,8 +4052,9 @@ static void nvme_add_ns_cdev(struct nvme_ns *ns) } static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ns *ns, - struct nvme_ns_info *info) - __must_hold(&ns->ctrl->subsys->lock) + struct nvme_subsystem *subsys, + struct nvme_ns_info *info) + __must_hold(&subsys->lock) { struct nvme_ctrl *ctrl = ns->ctrl; struct nvme_ns_head *head; @@ -4067,7 +4068,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ns *ns, head = kzalloc(size, GFP_KERNEL); if (!head) goto out; - ret = ida_alloc_min(&ctrl->subsys->ns_ida, 1, GFP_KERNEL); + ret = ida_alloc_min(&subsys->ns_ida, 1, GFP_KERNEL); if (ret < 0) goto out_free_head; head->instance = ret; @@ -4075,7 +4076,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ns *ns, ret = init_srcu_struct(&head->srcu); if (ret) goto out_ida_remove; - head->subsys = ctrl->subsys; + head->subsys = subsys; head->ns_id = info->nsid; head->ids = info->ids; head->shared = info->is_shared; @@ -4102,9 +4103,9 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ns *ns, if (ret) goto out_cleanup_fdp; - list_add_tail(&head->entry, &ctrl->subsys->nsheads); + list_add_tail(&head->entry, &subsys->nsheads); - kref_get(&ctrl->subsys->ref); + kref_get(&subsys->ref); return head; out_cleanup_fdp: @@ -4112,7 +4113,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ns *ns, out_cleanup_srcu: cleanup_srcu_struct(&head->srcu); out_ida_remove: - ida_free(&ctrl->subsys->ns_ida, head->instance); + ida_free(&subsys->ns_ida, head->instance); out_free_head: kfree(head); ns->head = NULL; @@ -4202,7 +4203,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info) info->nsid); goto out_unlock; } - head = nvme_alloc_ns_head(ns, info); + head = nvme_alloc_ns_head(ns, ctrl->subsys, info); if (IS_ERR(head)) { ret = PTR_ERR(head); goto out_unlock;