From 7bba9e81a6fbf00daa4063c41da6b250d339f43b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 11 Apr 2023 14:48:22 +0300 Subject: extcon: Use unique number for the extcon device ID The use of atomic variable is still racy when we do not control which device has been unregistered and there is a (theoretical) possibility of the overflow that may cause a duplicate extcon device ID number to be allocated next time a device is registered. Replace above mentioned approach by using IDA framework. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 16 +++++++++++++--- drivers/extcon/extcon.h | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 47819c5144d5..5da1cc60582a 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -238,6 +239,7 @@ struct extcon_cable { static struct class *extcon_class; +static DEFINE_IDA(extcon_dev_ids); static LIST_HEAD(extcon_dev_list); static DEFINE_MUTEX(extcon_dev_list_lock); @@ -1248,7 +1250,6 @@ static int extcon_alloc_groups(struct extcon_dev *edev) int extcon_dev_register(struct extcon_dev *edev) { int ret, index = 0; - static atomic_t edev_no = ATOMIC_INIT(-1); ret = create_extcon_class(); if (ret < 0) @@ -1275,8 +1276,14 @@ int extcon_dev_register(struct extcon_dev *edev) "extcon device name is null\n"); return -EINVAL; } - dev_set_name(&edev->dev, "extcon%lu", - (unsigned long)atomic_inc_return(&edev_no)); + + ret = ida_alloc(&extcon_dev_ids, GFP_KERNEL); + if (ret < 0) + return ret; + + edev->id = ret; + + dev_set_name(&edev->dev, "extcon%d", edev->id); ret = extcon_alloc_cables(edev); if (ret < 0) @@ -1339,6 +1346,7 @@ err_alloc_muex: if (edev->max_supported) kfree(edev->cables); err_alloc_cables: + ida_free(&extcon_dev_ids, edev->id); return ret; } @@ -1367,6 +1375,8 @@ void extcon_dev_unregister(struct extcon_dev *edev) return; } + ida_free(&extcon_dev_ids, edev->id); + device_unregister(&edev->dev); if (edev->mutually_exclusive && edev->max_supported) { diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h index 15616446140d..946182687786 100644 --- a/drivers/extcon/extcon.h +++ b/drivers/extcon/extcon.h @@ -20,6 +20,7 @@ * {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there * can be no simultaneous connections. * @dev: Device of this extcon. + * @id: Unique device ID of this extcon. * @state: Attach/detach state of this extcon. Do not provide at * register-time. * @nh_all: Notifier for the state change events for all supported @@ -46,6 +47,7 @@ struct extcon_dev { /* Internal data. Please do not set. */ struct device dev; + unsigned int id; struct raw_notifier_head nh_all; struct raw_notifier_head *nh; struct list_head entry; -- cgit v1.2.3