aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2013-09-18 16:02:00 -0400
committerJonathan Cameron <jic23@kernel.org>2013-09-21 07:50:23 -0400
commit0d5b7dae897b61a2372916b1c93f6cee6b8049b1 (patch)
treebfdaccfa0f8e614b42ebfa6e74871c1b653806ff /drivers/iio
parentcadc2125e140f7122bf1b59d42486cfc778c7286 (diff)
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 <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/industrialio-core.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 8f7b6c9f92dc..8e84cd522e49 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -848,8 +848,6 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
848static void iio_dev_release(struct device *device) 848static void iio_dev_release(struct device *device)
849{ 849{
850 struct iio_dev *indio_dev = dev_to_iio_dev(device); 850 struct iio_dev *indio_dev = dev_to_iio_dev(device);
851 if (indio_dev->chrdev.dev)
852 cdev_del(&indio_dev->chrdev);
853 if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) 851 if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
854 iio_device_unregister_trigger_consumer(indio_dev); 852 iio_device_unregister_trigger_consumer(indio_dev);
855 iio_device_unregister_eventset(indio_dev); 853 iio_device_unregister_eventset(indio_dev);
@@ -1056,18 +1054,20 @@ int iio_device_register(struct iio_dev *indio_dev)
1056 indio_dev->setup_ops == NULL) 1054 indio_dev->setup_ops == NULL)
1057 indio_dev->setup_ops = &noop_ring_setup_ops; 1055 indio_dev->setup_ops = &noop_ring_setup_ops;
1058 1056
1059 ret = device_add(&indio_dev->dev);
1060 if (ret < 0)
1061 goto error_unreg_eventset;
1062 cdev_init(&indio_dev->chrdev, &iio_buffer_fileops); 1057 cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
1063 indio_dev->chrdev.owner = indio_dev->info->driver_module; 1058 indio_dev->chrdev.owner = indio_dev->info->driver_module;
1059 indio_dev->chrdev.kobj.parent = &indio_dev->dev.kobj;
1064 ret = cdev_add(&indio_dev->chrdev, indio_dev->dev.devt, 1); 1060 ret = cdev_add(&indio_dev->chrdev, indio_dev->dev.devt, 1);
1065 if (ret < 0) 1061 if (ret < 0)
1066 goto error_del_device; 1062 goto error_unreg_eventset;
1067 return 0;
1068 1063
1069error_del_device: 1064 ret = device_add(&indio_dev->dev);
1070 device_del(&indio_dev->dev); 1065 if (ret < 0)
1066 goto error_cdev_del;
1067
1068 return 0;
1069error_cdev_del:
1070 cdev_del(&indio_dev->chrdev);
1071error_unreg_eventset: 1071error_unreg_eventset:
1072 iio_device_unregister_eventset(indio_dev); 1072 iio_device_unregister_eventset(indio_dev);
1073error_free_sysfs: 1073error_free_sysfs:
@@ -1085,6 +1085,9 @@ void iio_device_unregister(struct iio_dev *indio_dev)
1085 1085
1086 device_del(&indio_dev->dev); 1086 device_del(&indio_dev->dev);
1087 1087
1088 if (indio_dev->chrdev.dev)
1089 cdev_del(&indio_dev->chrdev);
1090
1088 iio_disable_all_buffers(indio_dev); 1091 iio_disable_all_buffers(indio_dev);
1089 1092
1090 indio_dev->info = NULL; 1093 indio_dev->info = NULL;