Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <andriy.shevchenko@linux.intel.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>

authored by

Andy Shevchenko and committed by
Chanwoo Choi
7bba9e81 566825a3

+15 -3
+13 -3
drivers/extcon/extcon.c
··· 16 16 17 17 #include <linux/module.h> 18 18 #include <linux/types.h> 19 + #include <linux/idr.h> 19 20 #include <linux/init.h> 20 21 #include <linux/device.h> 21 22 #include <linux/fs.h> ··· 239 238 240 239 static struct class *extcon_class; 241 240 241 + static DEFINE_IDA(extcon_dev_ids); 242 242 static LIST_HEAD(extcon_dev_list); 243 243 static DEFINE_MUTEX(extcon_dev_list_lock); 244 244 ··· 1250 1248 int extcon_dev_register(struct extcon_dev *edev) 1251 1249 { 1252 1250 int ret, index = 0; 1253 - static atomic_t edev_no = ATOMIC_INIT(-1); 1254 1251 1255 1252 ret = create_extcon_class(); 1256 1253 if (ret < 0) ··· 1276 1275 "extcon device name is null\n"); 1277 1276 return -EINVAL; 1278 1277 } 1279 - dev_set_name(&edev->dev, "extcon%lu", 1280 - (unsigned long)atomic_inc_return(&edev_no)); 1278 + 1279 + ret = ida_alloc(&extcon_dev_ids, GFP_KERNEL); 1280 + if (ret < 0) 1281 + return ret; 1282 + 1283 + edev->id = ret; 1284 + 1285 + dev_set_name(&edev->dev, "extcon%d", edev->id); 1281 1286 1282 1287 ret = extcon_alloc_cables(edev); 1283 1288 if (ret < 0) ··· 1346 1339 if (edev->max_supported) 1347 1340 kfree(edev->cables); 1348 1341 err_alloc_cables: 1342 + ida_free(&extcon_dev_ids, edev->id); 1349 1343 1350 1344 return ret; 1351 1345 } ··· 1374 1366 dev_err(&edev->dev, "Failed to unregister extcon_dev\n"); 1375 1367 return; 1376 1368 } 1369 + 1370 + ida_free(&extcon_dev_ids, edev->id); 1377 1371 1378 1372 device_unregister(&edev->dev); 1379 1373
+2
drivers/extcon/extcon.h
··· 20 20 * {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there 21 21 * can be no simultaneous connections. 22 22 * @dev: Device of this extcon. 23 + * @id: Unique device ID of this extcon. 23 24 * @state: Attach/detach state of this extcon. Do not provide at 24 25 * register-time. 25 26 * @nh_all: Notifier for the state change events for all supported ··· 47 46 48 47 /* Internal data. Please do not set. */ 49 48 struct device dev; 49 + unsigned int id; 50 50 struct raw_notifier_head nh_all; 51 51 struct raw_notifier_head *nh; 52 52 struct list_head entry;