Re: [PATCH v2 16/16] iio: core: move 'mlock' to 'struct iio_dev_opaque'

Andy Shevchenko
2022-10-04T14:23:15Z

On Tue, Oct 4, 2022 at 4:49 PM Nuno Sá <nuno.sa@analog.com> wrote:
>
> Now that there are no more users accessing 'mlock' directly, we can move
> it to the iio_dev private structure. Hence, it's now explicit that new
> driver's should not directly this lock.

use this

I like the end result!
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>

P.S. Shouldn't we annotate the respective APIs with might_sleep() and
Co (if it's not done yet)?

PPS Reading to the topic:
https://blog.ffwll.ch/2022/07/locking-engineering.html
https://blog.ffwll.ch/2022/08/locking-hierarchy.html
https://blog.ffwll.ch/2020/08/lockdep-false-positives.html

> Signed-off-by: Nuno Sá <nuno.sa@analog.com>
> ---
> drivers/iio/TODO | 3 ---
> drivers/iio/industrialio-buffer.c | 29 +++++++++++++++++------------
> drivers/iio/industrialio-core.c | 26 +++++++++++++++-----------
> drivers/iio/industrialio-event.c | 4 ++--
> drivers/iio/industrialio-trigger.c | 12 ++++++------
> include/linux/iio/iio-opaque.h | 2 ++
> include/linux/iio/iio.h | 3 ---
> 7 files changed, 42 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/iio/TODO b/drivers/iio/TODO
> index 7d7326b7085a..2ace27d1ac62 100644
> --- a/drivers/iio/TODO
> +++ b/drivers/iio/TODO
> @@ -7,9 +7,6 @@ tree
> - ABI Documentation
> - Audit driviers/iio/staging/Documentation
>
> -- Replace iio_dev->mlock by either a local lock or use
> -iio_claim_direct.(Requires analysis of the purpose of the lock.)
> -
> - Converting drivers from device tree centric to more generic
> property handlers.
>
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index 228598b82a2f..9cd7db549fcb 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -507,13 +507,14 @@ static ssize_t iio_scan_el_store(struct device *dev,
> int ret;
> bool state;
> struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
> struct iio_buffer *buffer = this_attr->buffer;
>
> ret = kstrtobool(buf, &state);
> if (ret < 0)
> return ret;
> - mutex_lock(&indio_dev->mlock);
> + mutex_lock(&iio_dev_opaque->mlock);
> if (iio_buffer_is_active(buffer)) {
> ret = -EBUSY;
> goto error_ret;
> @@ -532,7 +533,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
> }
>
> error_ret:
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
>
> return ret < 0 ? ret : len;
>
> @@ -554,6 +555,7 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
> {
> int ret;
> struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
> bool state;
>
> @@ -561,14 +563,14 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
> if (ret < 0)
> return ret;
>
> - mutex_lock(&indio_dev->mlock);
> + mutex_lock(&iio_dev_opaque->mlock);
> if (iio_buffer_is_active(buffer)) {
> ret = -EBUSY;
> goto error_ret;
> }
> buffer->scan_timestamp = state;
> error_ret:
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
>
> return ret ? ret : len;
> }
> @@ -642,6 +644,7 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr,
> const char *buf, size_t len)
> {
> struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
> unsigned int val;
> int ret;
> @@ -653,7 +656,7 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr,
> if (val == buffer->length)
> return len;
>
> - mutex_lock(&indio_dev->mlock);
> + mutex_lock(&iio_dev_opaque->mlock);
> if (iio_buffer_is_active(buffer)) {
> ret = -EBUSY;
> } else {
> @@ -665,7 +668,7 @@ static ssize_t length_store(struct device *dev, struct device_attribute *attr,
> if (buffer->length && buffer->length < buffer->watermark)
> buffer->watermark = buffer->length;
> out:
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
>
> return ret ? ret : len;
> }
> @@ -1256,7 +1259,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
> return -EINVAL;
>
> mutex_lock(&iio_dev_opaque->info_exist_lock);
> - mutex_lock(&indio_dev->mlock);
> + mutex_lock(&iio_dev_opaque->mlock);
>
> if (insert_buffer && iio_buffer_is_active(insert_buffer))
> insert_buffer = NULL;
> @@ -1277,7 +1280,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
> ret = __iio_update_buffers(indio_dev, insert_buffer, remove_buffer);
>
> out_unlock:
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
> mutex_unlock(&iio_dev_opaque->info_exist_lock);
>
> return ret;
> @@ -1296,6 +1299,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
> int ret;
> bool requested_state;
> struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
> bool inlist;
>
> @@ -1303,7 +1307,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
> if (ret < 0)
> return ret;
>
> - mutex_lock(&indio_dev->mlock);
> + mutex_lock(&iio_dev_opaque->mlock);
>
> /* Find out if it is in the list */
> inlist = iio_buffer_is_active(buffer);
> @@ -1317,7 +1321,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
> ret = __iio_update_buffers(indio_dev, NULL, buffer);
>
> done:
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
> return (ret < 0) ? ret : len;
> }
>
> @@ -1334,6 +1338,7 @@ static ssize_t watermark_store(struct device *dev,
> const char *buf, size_t len)
> {
> struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> struct iio_buffer *buffer = to_iio_dev_attr(attr)->buffer;
> unsigned int val;
> int ret;
> @@ -1344,7 +1349,7 @@ static ssize_t watermark_store(struct device *dev,
> if (!val)
> return -EINVAL;
>
> - mutex_lock(&indio_dev->mlock);
> + mutex_lock(&iio_dev_opaque->mlock);
>
> if (val > buffer->length) {
> ret = -EINVAL;
> @@ -1358,7 +1363,7 @@ static ssize_t watermark_store(struct device *dev,
>
> buffer->watermark = val;
> out:
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
>
> return ret ? ret : len;
> }
> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> index c23d3abb33c5..ebbc64e4f673 100644
> --- a/drivers/iio/industrialio-core.c
> +++ b/drivers/iio/industrialio-core.c
> @@ -285,16 +285,16 @@ int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
> struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> const struct iio_event_interface *ev_int = iio_dev_opaque->event_interface;
>
> - ret = mutex_lock_interruptible(&indio_dev->mlock);
> + ret = mutex_lock_interruptible(&iio_dev_opaque->mlock);
> if (ret)
> return ret;
> if ((ev_int && iio_event_enabled(ev_int)) ||
> iio_buffer_enabled(indio_dev)) {
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
> return -EBUSY;
> }
> iio_dev_opaque->clock_id = clock_id;
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
>
> return 0;
> }
> @@ -1674,7 +1674,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
> indio_dev->dev.type = &iio_device_type;
> indio_dev->dev.bus = &iio_bus_type;
> device_initialize(&indio_dev->dev);
> - mutex_init(&indio_dev->mlock);
> + mutex_init(&iio_dev_opaque->mlock);
> mutex_init(&iio_dev_opaque->info_exist_lock);
> INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list);
>
> @@ -1696,7 +1696,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
> INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers);
>
> lockdep_register_key(&iio_dev_opaque->mlock_key);
> - lockdep_set_class(&indio_dev->mlock, &iio_dev_opaque->mlock_key);
> + lockdep_set_class(&iio_dev_opaque->mlock, &iio_dev_opaque->mlock_key);
>
> return indio_dev;
> }
> @@ -2058,10 +2058,12 @@ EXPORT_SYMBOL_GPL(__devm_iio_device_register);
> */
> int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
> {
> - mutex_lock(&indio_dev->mlock);
> + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> +
> + mutex_lock(&iio_dev_opaque->mlock);
>
> if (iio_buffer_enabled(indio_dev)) {
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
> return -EBUSY;
> }
> return 0;
> @@ -2079,7 +2081,7 @@ EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode);
> */
> void iio_device_release_direct_mode(struct iio_dev *indio_dev)
> {
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock);
> }
> EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
>
> @@ -2096,12 +2098,14 @@ EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
> */
> int iio_device_claim_buffer_mode(struct iio_dev *indio_dev)
> {
> - mutex_lock(&indio_dev->mlock);
> + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> +
> + mutex_lock(&iio_dev_opaque->mlock);
>
> if (iio_buffer_enabled(indio_dev))
> return 0;
>
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
> return -EBUSY;
> }
> EXPORT_SYMBOL_GPL(iio_device_claim_buffer_mode);
> @@ -2117,7 +2121,7 @@ EXPORT_SYMBOL_GPL(iio_device_claim_buffer_mode);
> */
> void iio_device_release_buffer_mode(struct iio_dev *indio_dev)
> {
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&to_iio_dev_opaque(indio_dev)->mlock);
> }
> EXPORT_SYMBOL_GPL(iio_device_release_buffer_mode);
>
> diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
> index 3d78da2531a9..1a26393a7c0c 100644
> --- a/drivers/iio/industrialio-event.c
> +++ b/drivers/iio/industrialio-event.c
> @@ -198,7 +198,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
> if (ev_int == NULL)
> return -ENODEV;
>
> - fd = mutex_lock_interruptible(&indio_dev->mlock);
> + fd = mutex_lock_interruptible(&iio_dev_opaque->mlock);
> if (fd)
> return fd;
>
> @@ -219,7 +219,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
> }
>
> unlock:
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
> return fd;
> }
>
> diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
> index 6885a186fe27..a2f3cc2f65ef 100644
> --- a/drivers/iio/industrialio-trigger.c
> +++ b/drivers/iio/industrialio-trigger.c
> @@ -120,12 +120,12 @@ int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *tri
> return -EINVAL;
>
> iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> - mutex_lock(&indio_dev->mlock);
> + mutex_lock(&iio_dev_opaque->mlock);
> WARN_ON(iio_dev_opaque->trig_readonly);
>
> indio_dev->trig = iio_trigger_get(trig);
> iio_dev_opaque->trig_readonly = true;
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
>
> return 0;
> }
> @@ -438,16 +438,16 @@ static ssize_t current_trigger_store(struct device *dev,
> struct iio_trigger *trig;
> int ret;
>
> - mutex_lock(&indio_dev->mlock);
> + mutex_lock(&iio_dev_opaque->mlock);
> if (iio_dev_opaque->currentmode == INDIO_BUFFER_TRIGGERED) {
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
> return -EBUSY;
> }
> if (iio_dev_opaque->trig_readonly) {
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
> return -EPERM;
> }
> - mutex_unlock(&indio_dev->mlock);
> + mutex_unlock(&iio_dev_opaque->mlock);
>
> trig = iio_trigger_acquire_by_name(buf);
> if (oldtrig == trig) {
> diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h
> index d1f8b30a7c8b..5aec3945555b 100644
> --- a/include/linux/iio/iio-opaque.h
> +++ b/include/linux/iio/iio-opaque.h
> @@ -11,6 +11,7 @@
> * checked by device drivers but should be considered
> * read-only as this is a core internal bit
> * @driver_module: used to make it harder to undercut users
> + * @mlock: lock used to prevent simultaneous device state changes
> * @mlock_key: lockdep class for iio_dev lock
> * @info_exist_lock: lock to prevent use during removal
> * @trig_readonly: mark the current trigger immutable
> @@ -43,6 +44,7 @@ struct iio_dev_opaque {
> int currentmode;
> int id;
> struct module *driver_module;
> + struct mutex mlock;
> struct lock_class_key mlock_key;
> struct mutex info_exist_lock;
> bool trig_readonly;
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index 9d3bd6379eb8..8e0afaaa3f75 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -548,8 +548,6 @@ struct iio_buffer_setup_ops {
> * and owner
> * @buffer: [DRIVER] any buffer present
> * @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux
> - * @mlock: [INTERN] lock used to prevent simultaneous device state
> - * changes
> * @available_scan_masks: [DRIVER] optional array of allowed bitmasks
> * @masklength: [INTERN] the length of the mask established from
> * channels
> @@ -574,7 +572,6 @@ struct iio_dev {
>
> struct iio_buffer *buffer;
> int scan_bytes;
> - struct mutex mlock;
>
> const unsigned long *available_scan_masks;
> unsigned masklength;
> --
> 2.37.3
>

--
With Best Regards,
Andy Shevchenko