Skip to content

Commit

Permalink
extcon: Use unique number for the extcon device ID
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Chanwoo Choi <[email protected]>
  • Loading branch information
andy-shev authored and chanwoochoi committed May 29, 2023
1 parent 566825a commit 7bba9e8
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 3 deletions.
16 changes: 13 additions & 3 deletions drivers/extcon/extcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <linux/module.h>
#include <linux/types.h>
#include <linux/idr.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fs.h>
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -1339,6 +1346,7 @@ int extcon_dev_register(struct extcon_dev *edev)
if (edev->max_supported)
kfree(edev->cables);
err_alloc_cables:
ida_free(&extcon_dev_ids, edev->id);

return ret;
}
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 2 additions & 0 deletions drivers/extcon/extcon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down

0 comments on commit 7bba9e8

Please sign in to comment.