Skip to content

Commit 0d5b7da

Browse files
larsclausenjic23
authored andcommitted
iio: Prevent race between IIO chardev opening and IIO device free
Set the IIO device as the parent for the character device We need to make sure that the IIO device is not freed while the character device exists, otherwise the freeing of the IIO device might race against the file open callback. Do this by setting the character device's parent to the IIO device, this will cause the character device to grab a reference to the IIO device and only release it once the character device itself has been removed. Also move the registration of the character device before the registration of the IIO device to avoid the (rather theoretical case) that the IIO device is already freed again before we can add the character device and grab a reference to the IIO device. We also need to move the call to cdev_del() from iio_dev_release() to iio_device_unregister() (where it should have been in the first place anyway) to avoid a reference cycle. As iio_dev_release() is only called once all reference are dropped, but the character device holds a reference to the IIO device. Signed-off-by: Lars-Peter Clausen <[email protected]> Signed-off-by: Jonathan Cameron <[email protected]>
1 parent cadc212 commit 0d5b7da

File tree

1 file changed

+12
-9
lines changed

1 file changed

+12
-9
lines changed

drivers/iio/industrialio-core.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -848,8 +848,6 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
848848
static void iio_dev_release(struct device *device)
849849
{
850850
struct iio_dev *indio_dev = dev_to_iio_dev(device);
851-
if (indio_dev->chrdev.dev)
852-
cdev_del(&indio_dev->chrdev);
853851
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
854852
iio_device_unregister_trigger_consumer(indio_dev);
855853
iio_device_unregister_eventset(indio_dev);
@@ -1056,18 +1054,20 @@ int iio_device_register(struct iio_dev *indio_dev)
10561054
indio_dev->setup_ops == NULL)
10571055
indio_dev->setup_ops = &noop_ring_setup_ops;
10581056

1059-
ret = device_add(&indio_dev->dev);
1060-
if (ret < 0)
1061-
goto error_unreg_eventset;
10621057
cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
10631058
indio_dev->chrdev.owner = indio_dev->info->driver_module;
1059+
indio_dev->chrdev.kobj.parent = &indio_dev->dev.kobj;
10641060
ret = cdev_add(&indio_dev->chrdev, indio_dev->dev.devt, 1);
10651061
if (ret < 0)
1066-
goto error_del_device;
1067-
return 0;
1062+
goto error_unreg_eventset;
10681063

1069-
error_del_device:
1070-
device_del(&indio_dev->dev);
1064+
ret = device_add(&indio_dev->dev);
1065+
if (ret < 0)
1066+
goto error_cdev_del;
1067+
1068+
return 0;
1069+
error_cdev_del:
1070+
cdev_del(&indio_dev->chrdev);
10711071
error_unreg_eventset:
10721072
iio_device_unregister_eventset(indio_dev);
10731073
error_free_sysfs:
@@ -1085,6 +1085,9 @@ void iio_device_unregister(struct iio_dev *indio_dev)
10851085

10861086
device_del(&indio_dev->dev);
10871087

1088+
if (indio_dev->chrdev.dev)
1089+
cdev_del(&indio_dev->chrdev);
1090+
10881091
iio_disable_all_buffers(indio_dev);
10891092

10901093
indio_dev->info = NULL;

0 commit comments

Comments
 (0)