Since after the introduction of NVMe multipath, we have a struct to track subsystems, and more important, we have now the nvme block device name bound to the subsystem id instead of ctrl->instance as before. This is not a big problem, users can even fallback to the old behavior using the module parameter "nvme_core.multipath=N" in case they don't have multipath and wish to have a consistent mapping between the char device nvmeX and the block device nvmeXnY. That said, we noticed the nvme subsystem id is generated by its own ID allocator, and ctrl->instance value has itself an ID allocator too. The controller instance is generated during the probe, in the function nvme_init_ctrl(), which always executes before nvme_init_subsystem(). That said, and since according to the spec we have a relation 1:N between subsystem and controllers (i.e., one subsystem may have more controllers but not the reciprocal), why not use the ctrl->instance id as the subsystem id? This patch does exactly this: removes the ID allocator for subsystems and use the unique controller instance id as subsystem id. The patch was tested in multiple scenarios, like: * multiple controllers (each one tied to its own subsystem); * 2 controllers in a single subsystem (using emulated nvme controllers from qemu). In this case, subsystem gets the id of its 1st controller; * NVMEoF/TCP with this patch in both target and host kernels. All test cases worked as expected. With this patch, the "coincidence" of the char device number matches the block device number is forced for single-controllers subsystems (the most usual scenario), even without disabling multipath. It's useful for scenarios with some multipath'ed controllers and some solo controllers. Signed-off-by: Guilherme G. Piccoli <gpiccoli@xxxxxxxxxxxxx> --- drivers/nvme/host/core.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index cca270836892..60631e856b41 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -81,7 +81,6 @@ EXPORT_SYMBOL_GPL(nvme_reset_wq); struct workqueue_struct *nvme_delete_wq; EXPORT_SYMBOL_GPL(nvme_delete_wq); -static DEFINE_IDA(nvme_subsystems_ida); static LIST_HEAD(nvme_subsystems); static DEFINE_MUTEX(nvme_subsystems_lock); @@ -2316,7 +2315,6 @@ static void nvme_release_subsystem(struct device *dev) struct nvme_subsystem *subsys = container_of(dev, struct nvme_subsystem, dev); - ida_simple_remove(&nvme_subsystems_ida, subsys->instance); kfree(subsys); } @@ -2445,12 +2443,8 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) subsys = kzalloc(sizeof(*subsys), GFP_KERNEL); if (!subsys) return -ENOMEM; - ret = ida_simple_get(&nvme_subsystems_ida, 0, 0, GFP_KERNEL); - if (ret < 0) { - kfree(subsys); - return ret; - } - subsys->instance = ret; + + subsys->instance = ctrl->instance; mutex_init(&subsys->lock); kref_init(&subsys->ref); INIT_LIST_HEAD(&subsys->ctrls); @@ -4051,7 +4045,6 @@ static int __init nvme_core_init(void) static void __exit nvme_core_exit(void) { - ida_destroy(&nvme_subsystems_ida); class_destroy(nvme_subsys_class); class_destroy(nvme_class); unregister_chrdev_region(nvme_chr_devt, NVME_MINORS); -- 2.22.0