linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alexandru Ardelean <ardeleanalex@gmail.com>
To: Jonathan Cameron <jic23@kernel.org>
Cc: Alexandru Ardelean <alexandru.ardelean@analog.com>,
	linux-iio <linux-iio@vger.kernel.org>,
	LKML <linux-kernel@vger.kernel.org>,
	Lars-Peter Clausen <lars@metafoo.de>
Subject: Re: [RFC PATCH 12/12] iio: buffer: add ioctl() to support opening extra buffers for IIO device
Date: Mon, 23 Nov 2020 14:54:47 +0200	[thread overview]
Message-ID: <CA+U=DspvdaLOsjuU3VPnh4L94+WQeepcWi8iUkphGAnp=xOj5g@mail.gmail.com> (raw)
In-Reply-To: <20201121185041.7a0649f7@archlinux>

On Sat, Nov 21, 2020 at 8:53 PM Jonathan Cameron <jic23@kernel.org> wrote:
>
> On Tue, 17 Nov 2020 18:23:40 +0200
> Alexandru Ardelean <alexandru.ardelean@analog.com> wrote:
>
> > With this change, an ioctl() call is added to open a character device for a
> > buffer.
> > The ioctl() will not work for the first buffer, as that buffer is already
> > opened/reserved for the IIO device's character device.
> > This is also to preserve backwards compatibility.
> >
> > For any other extra buffer (after the first buffer) this ioctl() will be
> > required.
>
> Silly question, but can we have the ioctl just return the file handle for
> the buffer itself if called on index 0?

I also was thinking about this initially, but I'm not sure yet how to do it.
I'd need to dig into it.
Or find out where to dig this out from the 'struct file' type or wherever.
I initially started digging through anon_inode_getfd()  help, but it
didn't quite help.
I ended up in 'fs/anon_inodes.c',' 'fs/file.c' and
'include/linux/file.h', and the only thing you can seem to be able do
(at first glance) is to request and unused FD, and assigin a 'struct
file' object to it.

I may have missed something, but if that is the case, this ioctl()
would give you another FD for the same buffer zero.
First FD is the one used for the ioctl() (which can also do buffer
transfers), and second one is the one returned by this ioctl(), which
sounds like it could allow some mess in userspace code.

In case this isn't possible in a sane way, the only thing that can be
done is to indicate to the user that "hey, you already have an FD for
buffer 0, so use it".

>
> Would make for slightly more natural userspace code even though it
> doesn't do anything...
>
> >
> > Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
> > ---
> >  drivers/iio/industrialio-buffer.c | 111 ++++++++++++++++++++++++++++++
> >  drivers/iio/industrialio-core.c   |   8 +++
> >  include/linux/iio/buffer_impl.h   |   5 ++
> >  include/linux/iio/iio-opaque.h    |   2 +
> >  include/uapi/linux/iio/buffer.h   |  16 +++++
> >  5 files changed, 142 insertions(+)
> >  create mode 100644 include/uapi/linux/iio/buffer.h
> >
> > diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> > index daa68822cea7..77f02870cd18 100644
> > --- a/drivers/iio/industrialio-buffer.c
> > +++ b/drivers/iio/industrialio-buffer.c
> > @@ -9,6 +9,7 @@
> >   * - Better memory allocation techniques?
> >   * - Alternative access techniques?
> >   */
> > +#include <linux/anon_inodes.h>
> >  #include <linux/kernel.h>
> >  #include <linux/export.h>
> >  #include <linux/device.h>
> > @@ -1399,6 +1400,99 @@ static void iio_sysfs_del_attrs(struct kobject *kobj, struct attribute **ptr)
> >               sysfs_remove_file(kobj, ptr[i]);
> >  }
> >
> > +static int iio_buffer_chrdev_release(struct inode *inode, struct file *filep)
> > +{
> > +     struct iio_dev_buffer_pair *ib = filep->private_data;
> > +     struct iio_dev *indio_dev = ib->indio_dev;
> > +     struct iio_buffer *buffer = ib->buffer;
> > +
> > +     clear_bit(IIO_BUSY_BIT_POS, &buffer->flags);
> > +     iio_device_put(indio_dev);
> > +     kfree(ib);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct file_operations iio_buffer_chrdev_fileops = {
> > +     .owner = THIS_MODULE,
> > +     .llseek = noop_llseek,
> > +     .read = iio_buffer_read_outer_addr,
> > +     .poll = iio_buffer_poll_addr,
> > +     .compat_ioctl = compat_ptr_ioctl,
> > +     .release = iio_buffer_chrdev_release,
> > +};
> > +
> > +static long iio_device_buffer_getfd(struct iio_dev *indio_dev, unsigned long arg)
> > +{
> > +     struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> > +     int __user *ival = (int __user *)arg;
> > +     char buf_name[sizeof("iio:buffer:xxx")];
> > +     struct iio_dev_buffer_pair *ib;
> > +     struct iio_buffer *buffer;
> > +     int fd, idx;
> > +
> > +     if (copy_from_user(&idx, ival, sizeof(idx)))
> > +             return -EFAULT;
> > +
> > +     if (idx >= iio_dev_opaque->attached_buffers_cnt)
> > +             return -ENOENT;
> > +
> > +     fd = mutex_lock_interruptible(&indio_dev->mlock);
> > +     if (fd)
> > +             return fd;
> > +
> > +     buffer = iio_dev_opaque->attached_buffers[idx];
> > +
> > +     if (test_and_set_bit(IIO_BUSY_BIT_POS, &buffer->flags)) {
> > +             fd = -EBUSY;
> > +             goto error_unlock;
> > +     }
> > +
> > +     iio_device_get(indio_dev);
> > +
> > +     ib = kzalloc(sizeof(*ib), GFP_KERNEL);
> > +     if (!ib) {
> > +             fd = -ENOMEM;
> > +             goto error_iio_dev_put;
> > +     }
> > +
> > +     ib->indio_dev = indio_dev;
> > +     ib->buffer = buffer;
> > +
> > +     fd = anon_inode_getfd(buf_name, &iio_buffer_chrdev_fileops,
> > +                           ib, O_RDWR | O_CLOEXEC);
> > +     if (fd < 0)
> > +             goto error_free_ib;
> > +
> > +     if (copy_to_user(ival, &fd, sizeof(fd))) {
> > +             fd = -EFAULT;
> > +             goto error_free_ib;
> > +     }
> > +
> > +     mutex_unlock(&indio_dev->mlock);
> > +     return fd;
> > +
> > +error_free_ib:
> > +     kfree(ib);
> > +error_iio_dev_put:
> > +     iio_device_put(indio_dev);
> > +     clear_bit(IIO_BUSY_BIT_POS, &buffer->flags);
> > +error_unlock:
> > +     mutex_unlock(&indio_dev->mlock);
> > +     return fd;
> > +}
> > +
> > +static long iio_device_buffer_ioctl(struct iio_dev *indio_dev, struct file *filp,
> > +                                 unsigned int cmd, unsigned long arg)
> > +{
> > +     switch (cmd) {
> > +     case IIO_BUFFER_GET_FD_IOCTL:
> > +             return iio_device_buffer_getfd(indio_dev, arg);
> > +     default:
> > +             return IIO_IOCTL_UNHANDLED;
> > +     }
> > +}
> > +
> >  static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
> >                                            struct iio_dev *indio_dev,
> >                                            unsigned int idx)
> > @@ -1549,8 +1643,21 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
> >       if (ret)
> >               goto error_remove_buffer_dir_link;
> >
> > +     i = sizeof(*(iio_dev_opaque->buffer_ioctl_handler));
>
> using i for that isn't particularly readable.  Add a sz or similar local
> variable for it.

ack

>
> > +     iio_dev_opaque->buffer_ioctl_handler = kzalloc(i, GFP_KERNEL);
> > +     if (!iio_dev_opaque->buffer_ioctl_handler) {
> > +             ret = -ENOMEM;
> > +             goto error_remove_scan_el_dir;
> > +     }
> > +
> > +     iio_dev_opaque->buffer_ioctl_handler->ioctl = iio_device_buffer_ioctl;
> > +     iio_device_ioctl_handler_register(indio_dev,
> > +                                       iio_dev_opaque->buffer_ioctl_handler);
> > +
> >       return 0;
> >
> > +error_remove_scan_el_dir:
> > +     sysfs_remove_link(&indio_dev->dev.kobj, "scan_elements");
> >  error_remove_buffer_dir_link:
> >       sysfs_remove_link(&indio_dev->dev.kobj, "buffer");
> >       i = iio_dev_opaque->attached_buffers_cnt - 1;
> > @@ -1585,6 +1692,10 @@ void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev)
> >       if (!buffer)
> >               return;
> >
> > +     iio_device_ioctl_handler_unregister(iio_dev_opaque->buffer_ioctl_handler);
> > +     kfree(iio_dev_opaque->buffer_ioctl_handler);
> > +     iio_dev_opaque->buffer_ioctl_handler = NULL;
> > +
> >       sysfs_remove_link(&indio_dev->dev.kobj, "scan_elements");
> >       sysfs_remove_link(&indio_dev->dev.kobj, "buffer");
> >
> > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> > index 9e7a76723f00..b4f7dd75bef5 100644
> > --- a/drivers/iio/industrialio-core.c
> > +++ b/drivers/iio/industrialio-core.c
> > @@ -1685,6 +1685,9 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
> >       ib->indio_dev = indio_dev;
> >       ib->buffer = indio_dev->buffer;
> >
> > +     if (indio_dev->buffer)
> > +             test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->buffer->flags);
> > +
> >       filp->private_data = ib;
> >
> >       return 0;
> > @@ -1702,6 +1705,11 @@ static int iio_chrdev_release(struct inode *inode, struct file *filp)
> >       struct iio_dev_buffer_pair *ib = filp->private_data;
> >       struct iio_dev *indio_dev = container_of(inode->i_cdev,
> >                                               struct iio_dev, chrdev);
> > +     struct iio_buffer *buffer = ib->buffer;
> > +
> > +     if (buffer)
> > +             clear_bit(IIO_BUSY_BIT_POS, &buffer->flags);
> > +
> >       clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
> >       iio_device_put(indio_dev);
> >       kfree(ib);
> > diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h
> > index e25d26a7f601..78da590b5607 100644
> > --- a/include/linux/iio/buffer_impl.h
> > +++ b/include/linux/iio/buffer_impl.h
> > @@ -6,6 +6,8 @@
> >
> >  #ifdef CONFIG_IIO_BUFFER
> >
> > +#include <uapi/linux/iio/buffer.h>
> > +
> >  struct iio_dev;
> >  struct iio_buffer;
> >
> > @@ -75,6 +77,9 @@ struct iio_buffer {
> >       /** @length: Number of datums in buffer. */
> >       unsigned int length;
> >
> > +     /** @flags: File ops flags including busy flag. */
> > +     unsigned long flags;
> > +
> >       /**  @bytes_per_datum: Size of individual datum including timestamp. */
> >       size_t bytes_per_datum;
> >
> > diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h
> > index 1db0ea09520e..d0429b13afa8 100644
> > --- a/include/linux/iio/iio-opaque.h
> > +++ b/include/linux/iio/iio-opaque.h
> > @@ -9,6 +9,7 @@
> >   * @event_interface:         event chrdevs associated with interrupt lines
> >   * @attached_buffers:                array of buffers statically attached by the driver
> >   * @attached_buffers_cnt:    number of buffers in the array of statically attached buffers
> > + * @buffer_ioctl_handler:    ioctl() handler for this IIO device's buffer interface
> >   * @buffer_list:             list of all buffers currently attached
> >   * @channel_attr_list:               keep track of automatically created channel
> >   *                           attributes
> > @@ -24,6 +25,7 @@ struct iio_dev_opaque {
> >       struct iio_event_interface      *event_interface;
> >       struct iio_buffer               **attached_buffers;
> >       unsigned int                    attached_buffers_cnt;
> > +     struct iio_ioctl_handler        *buffer_ioctl_handler;
> >       struct list_head                buffer_list;
> >       struct list_head                channel_attr_list;
> >       struct attribute_group          chan_attr_group;
> > diff --git a/include/uapi/linux/iio/buffer.h b/include/uapi/linux/iio/buffer.h
> > new file mode 100644
> > index 000000000000..3794eca78dad
> > --- /dev/null
> > +++ b/include/uapi/linux/iio/buffer.h
> > @@ -0,0 +1,16 @@
> > +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> > +/* industrial I/O buffer definitions needed both in and out of kernel
> > + *
> > + * Copyright (c) 2020 Alexandru Ardelean
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms of the GNU General Public License version 2 as published by
> > + * the Free Software Foundation.
> > + */
> > +
> > +#ifndef _UAPI_IIO_BUFFER_H_
> > +#define _UAPI_IIO_BUFFER_H_
> > +
> > +#define IIO_BUFFER_GET_FD_IOCTL              _IOWR('i', 0xa0, int)
> Is it more sensible to just have that alongside the other IOCTLs rather than
> defining a new header for it?

If I didn't miss anything, the only other ioctl() is in
'include/uapi/linux/iio/events.h'
Which didn't seem logical to extend with this.

I can move it into events.h, but there will be more buffer ioctl()
calls anyway coming.
The ones we have now are here [Linux and libiio]:
https://github.com/analogdevicesinc/linux/blob/master/include/linux/iio/buffer_impl.h#L12
https://github.com/analogdevicesinc/libiio/blob/master/local.c#L51

I'm still trying to see how to make these backwards compatible with
our old ioctl() calls.
Maybe, one idea is that this gets moved to index 0xa5.
Or we just go to 0xb0 directly?


>
> If not available I guess we'd just get an -EINVAL response, so harmless.
>
> > +
> > +#endif /* _UAPI_IIO_BUFFER_H_ */
>

  reply	other threads:[~2020-11-23 12:55 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-17 16:23 [RFC PATCH 00/12] iio: core,buffer: add support for multiple IIO buffers per IIO device Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 01/12] iio: core: register chardev only if needed Alexandru Ardelean
2020-11-21 18:02   ` Jonathan Cameron
2020-11-23 12:10     ` Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 02/12] iio: buffer: add back-ref from iio_buffer to iio_dev Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 03/12] iio: buffer: rework buffer & scan_elements dir creation Alexandru Ardelean
2020-11-21 18:24   ` Jonathan Cameron
2020-11-23 12:21     ` Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 04/12] iio: buffer: add index to the first IIO buffer dir and symlink it back Alexandru Ardelean
2020-11-21 18:27   ` Jonathan Cameron
2020-11-17 16:23 ` [RFC PATCH 05/12] iio: core: split __iio_device_attr_init() to init only the attr object Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 06/12] iio: buffer: re-route scan_elements via it's kobj_type Alexandru Ardelean
2020-11-21 18:33   ` Jonathan Cameron
2020-11-23 12:22     ` Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 07/12] iio: buffer: re-route core buffer attributes via it's new kobj_type Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 08/12] iio: buffer: add helper to get the IIO device to which a buffer belongs Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 09/12] iio: re-route all buffer attributes through new buffer kobj_type Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 10/12] iio: core: wrap iio device & buffer into struct for character devices Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 11/12] iio: buffer: introduce support for attaching more IIO buffers Alexandru Ardelean
2020-11-21 18:44   ` Jonathan Cameron
2020-11-23 12:27     ` Alexandru Ardelean
2020-11-17 16:23 ` [RFC PATCH 12/12] iio: buffer: add ioctl() to support opening extra buffers for IIO device Alexandru Ardelean
2020-11-21 18:50   ` Jonathan Cameron
2020-11-23 12:54     ` Alexandru Ardelean [this message]
2020-11-21 18:52 ` [RFC PATCH 00/12] iio: core,buffer: add support for multiple IIO buffers per " Jonathan Cameron
2020-11-23 13:03   ` Alexandru Ardelean

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CA+U=DspvdaLOsjuU3VPnh4L94+WQeepcWi8iUkphGAnp=xOj5g@mail.gmail.com' \
    --to=ardeleanalex@gmail.com \
    --cc=alexandru.ardelean@analog.com \
    --cc=jic23@kernel.org \
    --cc=lars@metafoo.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).