i2c_dev_init() first registers a bus notifier and only then walks the adapters that are already registered: res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); if (res) goto out_unreg_class; /* Bind to already existing adapters right away */ i2c_for_each_dev(NULL, i2c_dev_attach_adapter); device_add() links a new device into the bus klist in bus_add_device(), which runs before BUS_NOTIFY_ADD_DEVICE is emitted. An adapter that is registered while i2c_dev_init() is running can therefore be observed by both paths: the notifier creates its chardev, and i2c_for_each_dev(), which has no way to tell that the notifier already ran, tries to create it a second time. The second cdev_device_add() fails with -EEXIST: sysfs: cannot create duplicate filename '/devices/platform/mlxplat/i2c_mlxcpld.1/i2c-1/i2c-2/i2c-dev/i2c-2' Call Trace: dump_stack_lvl+0x5d/0x80 sysfs_warn_dup.cold+0x17/0x23 sysfs_create_dir_ns+0xca/0xe0 kobject_add_internal+0xba/0x250 kobject_add+0x96/0xc0 device_add+0xe2/0x890 cdev_device_add+0x48/0x90 i2cdev_attach_adapter+0x137/0x170 [i2c_dev] i2c_dev_attach_adapter+0xe/0xf60 [i2c_dev] bus_for_each_dev+0x88/0xe0 i2c_for_each_dev+0x31/0x50 i2c_dev_init+0x77/0xa0 [i2c_dev] do_one_initcall+0x58/0x2f0 do_init_module+0x60/0x230 kobject: kobject_add_internal failed for i2c-2 with -EEXIST, don't try to register things with the same name in the same directory. This is reproducible on systems where adapters appear asynchronously while i2c-dev is being loaded, for example when an i2c mux instantiates its child adapters from a deferred probe. Registering the notifier before walking the bus is intentional, as the reverse order would silently miss adapters registered in between, so the attach path has to tolerate being called twice for the same adapter. Make it idempotent: look for an existing i2c_dev while holding i2c_dev_list_lock, which serialises the lookup against a parallel insertion, and let the loser return -EBUSY. i2cdev_attach_adapter() already ignores get_free_i2c_dev() failures, so it just backs off. Matching on adap->nr rather than on the adapter pointer cannot reject a live adapter that reused the number of a departing one: i2c_del_adapter() returns the number to i2c_adapter_idr only after device_unregister() has run the bus notifier that unlinks the outgoing i2c_dev. The number is also what has to be unique here, as it is both the chardev minor and the "i2c-%d" sysfs name, and it is the key i2c_dev_get_by_minor() looks up. Fixes: 9ea3e941d161 ("i2c-dev: Use standard bus notification mechanism") Cc: stable@vger.kernel.org Signed-off-by: Felix Radensky --- v1->v2: - Explain in the commit message and in a comment why the lookup keys on adap->nr and why that cannot reject a live adapter which reused the number of a departing one. No code change. v1: https://lore.kernel.org/linux-i2c/20260908095016.1050174-1-fradensky@nvidia.com/ v1 received no review comments. drivers/i2c/i2c-dev.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index d219eb8..011fa95 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -67,7 +67,7 @@ found: static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap) { - struct i2c_dev *i2c_dev; + struct i2c_dev *i2c_dev, *tmp; if (adap->nr >= I2C_MINORS) { pr_err("Out of device minors (%d)\n", adap->nr); @@ -80,6 +80,19 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap) i2c_dev->adap = adap; spin_lock(&i2c_dev_list_lock); + /* + * i2c_del_adapter() returns the adapter number to the idr only after + * device_unregister() has run the bus notifier that unlinks the + * outgoing i2c_dev, so a match here is always this very adapter, + * already attached by the other i2c_dev_init() path. + */ + list_for_each_entry(tmp, &i2c_dev_list, list) { + if (tmp->adap->nr == adap->nr) { + spin_unlock(&i2c_dev_list_lock); + kfree(i2c_dev); + return ERR_PTR(-EBUSY); + } + } list_add_tail(&i2c_dev->list, &i2c_dev_list); spin_unlock(&i2c_dev_list_lock); return i2c_dev; base-commit: fa4ad798f6f681031775266044ba1b0cf3c670bd -- 2.34.1