Re: [PATCH v2] iio: Use per-device lockdep class for mlock

From: Andy Shevchenko
Date: Mon Aug 29 2022 - 06:28:55 EST


On Mon, Aug 29, 2022 at 12:18 PM Vincent Whitchurch
<vincent.whitchurch@xxxxxxxx> wrote:
>
> If an IIO driver uses callbacks from another IIO driver and calls
> iio_channel_start_all_cb() from one of its buffer setup ops, then
> lockdep complains due to the lock nesting, as in the below example with
> lmp91000.
>
> Since the locks are being taken on different IIO devices, there is no
> actual deadlock. Fix the warning by telling lockdep to use a different
> class for each iio_device.
>
> ============================================
> WARNING: possible recursive locking detected
> --------------------------------------------
> python3/23 is trying to acquire lock:
> (&indio_dev->mlock){+.+.}-{3:3}, at: iio_update_buffers
>
> but task is already holding lock:
> (&indio_dev->mlock){+.+.}-{3:3}, at: enable_store
>
> other info that might help us debug this:
> Possible unsafe locking scenario:
>
> CPU0
> ----
> lock(&indio_dev->mlock);
> lock(&indio_dev->mlock);
>
> *** DEADLOCK ***
>
> May be due to missing lock nesting notation
>
> 5 locks held by python3/23:
> #0: (sb_writers#5){.+.+}-{0:0}, at: ksys_write
> #1: (&of->mutex){+.+.}-{3:3}, at: kernfs_fop_write_iter
> #2: (kn->active#14){.+.+}-{0:0}, at: kernfs_fop_write_iter
> #3: (&indio_dev->mlock){+.+.}-{3:3}, at: enable_store
> #4: (&iio_dev_opaque->info_exist_lock){+.+.}-{3:3}, at: iio_update_buffers
>
> Call Trace:
> __mutex_lock
> iio_update_buffers
> iio_channel_start_all_cb
> lmp91000_buffer_postenable
> __iio_update_buffers
> enable_store


This looks much better than the previous version, thanks!
Reviewed-by: Andy Shevchenko <andy.shevchenko@xxxxxxxxx>

> Fixes: 67e17300dc1d76 ("iio: potentiostat: add LMP91000 support")
> Signed-off-by: Vincent Whitchurch <vincent.whitchurch@xxxxxxxx>
> ---
>
> Notes:
> v2:
> - Use a different lockdep class for each iio_device, instead of using
> mutex_lock_nested.
> - Add fixes tag pointing to first IIO driver which used this API.
> - Trim call stack in commit message.
>
> drivers/iio/industrialio-core.c | 5 +++++
> include/linux/iio/iio-opaque.h | 2 ++
> 2 files changed, 7 insertions(+)
>
> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> index 0f4dbda3b9d3..921d8e8643a2 100644
> --- a/drivers/iio/industrialio-core.c
> +++ b/drivers/iio/industrialio-core.c
> @@ -1621,6 +1621,8 @@ static void iio_dev_release(struct device *device)
>
> iio_device_detach_buffers(indio_dev);
>
> + lockdep_unregister_key(&iio_dev_opaque->mlock_key);
> +
> ida_free(&iio_ida, iio_dev_opaque->id);
> kfree(iio_dev_opaque);
> }
> @@ -1680,6 +1682,9 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
> INIT_LIST_HEAD(&iio_dev_opaque->buffer_list);
> 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);
> +
> return indio_dev;
> }
> EXPORT_SYMBOL(iio_device_alloc);
> diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h
> index 6b3586b3f952..d1f8b30a7c8b 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_key: lockdep class for iio_dev lock
> * @info_exist_lock: lock to prevent use during removal
> * @trig_readonly: mark the current trigger immutable
> * @event_interface: event chrdevs associated with interrupt lines
> @@ -42,6 +43,7 @@ struct iio_dev_opaque {
> int currentmode;
> int id;
> struct module *driver_module;
> + struct lock_class_key mlock_key;
> struct mutex info_exist_lock;
> bool trig_readonly;
> struct iio_event_interface *event_interface;
> --
> 2.34.1
>


--
With Best Regards,
Andy Shevchenko