Re: [PATCH v6 20/24] iio: buffer: add ioctl() to support opening extra buffers for IIO device
From: Alexandru Ardelean <hidden>
Date: 2021-02-28 18:05:55
Also in:
lkml
On Sun, Feb 28, 2021 at 9:58 AM Lars-Peter Clausen [off-list ref] wrote:
On 2/15/21 11:40 AM, Alexandru Ardelean wrote:quoted
[...] /** * iio_buffer_wakeup_poll - Wakes up the buffer waitqueue * @indio_dev: The IIO device@@ -1343,6 +1371,96 @@ static void iio_buffer_unregister_legacy_sysfs_groups(struct iio_dev *indio_dev) kfree(iio_dev_opaque->legacy_scan_el_group.attrs); }[...] +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; + struct iio_dev_buffer_pair *ib; + struct iio_buffer *buffer; + int fd, idx, ret; + + if (copy_from_user(&idx, ival, sizeof(idx))) + return -EFAULT;If we only want to pass an int, we can pass that directly, no need to pass it as a pointer. int fd = arg;
I guess I can simplify this a bit.
quoted
+ + if (idx >= iio_dev_opaque->attached_buffers_cnt) + return -ENODEV; + + iio_device_get(indio_dev); + + buffer = iio_dev_opaque->attached_buffers[idx]; + + if (test_and_set_bit(IIO_BUSY_BIT_POS, &buffer->flags)) { + ret = -EBUSY; + goto error_iio_dev_put; + } + + ib = kzalloc(sizeof(*ib), GFP_KERNEL); + if (!ib) { + ret = -ENOMEM; + goto error_clear_busy_bit; + } + + ib->indio_dev = indio_dev; + ib->buffer = buffer; + + fd = anon_inode_getfd("iio:buffer", &iio_buffer_chrdev_fileops, + ib, O_RDWR | O_CLOEXEC);I wonder if we need to allow to pass flags, like e.g. O_NONBLOCK. Something like https://elixir.bootlin.com/linux/latest/source/fs/signalfd.c#L288
Umm, no idea.
I guess we could.
Would a syscall make more sense than an ioctl() here?
I guess for the ioctl() case we would need to change the type (of the
data) to some sort of
struct iio_buffer_get_fd {
unsigned int buffer_idx;
unsigned int fd_flags;
};
Or do we just let userspace use fcntl() to change flags to O_NONBLOCK ?
quoted
+ if (fd < 0) { + ret = fd; + goto error_free_ib; + } + + if (copy_to_user(ival, &fd, sizeof(fd))) { + put_unused_fd(fd); + ret = -EFAULT; + goto error_free_ib; + }Here we copy back the fd, but also return it. Just return is probably enough.
Hmm. Yes, it is a bit duplicate. But it is a good point. Maybe we should return 0 to userspace.
quoted
+ + return fd; + +error_free_ib: + kfree(ib); +error_clear_busy_bit: + clear_bit(IIO_BUSY_BIT_POS, &buffer->flags); +error_iio_dev_put: + iio_device_put(indio_dev); + return ret; +} [...]diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h index b6ebc04af3e7..32addd5e790e 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@@ -28,6 +29,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;Can we just embedded this struct so we do not have to allocate/deallocate it?
Unfortunately we can't. The type of ' struct iio_ioctl_handler ' is stored in iio_core.h. So, we don't know the size here. So we need to keep it as a pointer and allocate it. It is a bit of an unfortunate consequence of the design of this generic ioctl() registering.
quoted
struct list_head buffer_list; struct list_head channel_attr_list; struct attribute_group chan_attr_group;