Commit 20bddcb4 authored by Kent Gibson's avatar Kent Gibson Committed by Bartosz Golaszewski
Browse files

gpiolib: cdev: replace locking wrappers for gpio_device with guards



Replace the wrapping functions that inhibit removal of the gpio chip
with equivalent guards.

Signed-off-by: default avatarKent Gibson <warthog618@gmail.com>
Signed-off-by: default avatarBartosz Golaszewski <bartosz.golaszewski@linaro.org>
parent 32d8e3b6
Loading
Loading
Loading
Loading
+47 −158
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/poll.h>
#include <linux/rbtree.h>
#include <linux/rwsem.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/timekeeping.h>
@@ -65,45 +66,6 @@ typedef long (*ioctl_fn)(struct file *, unsigned int, unsigned long);
typedef ssize_t (*read_fn)(struct file *, char __user *,
			   size_t count, loff_t *);

static __poll_t call_poll_locked(struct file *file,
				 struct poll_table_struct *wait,
				 struct gpio_device *gdev, poll_fn func)
{
	__poll_t ret;

	down_read(&gdev->sem);
	ret = func(file, wait);
	up_read(&gdev->sem);

	return ret;
}

static long call_ioctl_locked(struct file *file, unsigned int cmd,
			      unsigned long arg, struct gpio_device *gdev,
			      ioctl_fn func)
{
	long ret;

	down_read(&gdev->sem);
	ret = func(file, cmd, arg);
	up_read(&gdev->sem);

	return ret;
}

static ssize_t call_read_locked(struct file *file, char __user *buf,
				size_t count, loff_t *f_ps,
				struct gpio_device *gdev, read_fn func)
{
	ssize_t ret;

	down_read(&gdev->sem);
	ret = func(file, buf, count, f_ps);
	up_read(&gdev->sem);

	return ret;
}

/*
 * GPIO line handle management
 */
@@ -238,7 +200,7 @@ static long linehandle_set_config(struct linehandle_state *lh,
	return 0;
}

static long linehandle_ioctl_unlocked(struct file *file, unsigned int cmd,
static long linehandle_ioctl(struct file *file, unsigned int cmd,
			     unsigned long arg)
{
	struct linehandle_state *lh = file->private_data;
@@ -248,6 +210,8 @@ static long linehandle_ioctl_unlocked(struct file *file, unsigned int cmd,
	unsigned int i;
	int ret;

	guard(rwsem_read)(&lh->gdev->sem);

	if (!lh->gdev->chip)
		return -ENODEV;

@@ -297,15 +261,6 @@ static long linehandle_ioctl_unlocked(struct file *file, unsigned int cmd,
	}
}

static long linehandle_ioctl(struct file *file, unsigned int cmd,
			     unsigned long arg)
{
	struct linehandle_state *lh = file->private_data;

	return call_ioctl_locked(file, cmd, arg, lh->gdev,
				 linehandle_ioctl_unlocked);
}

#ifdef CONFIG_COMPAT
static long linehandle_ioctl_compat(struct file *file, unsigned int cmd,
				    unsigned long arg)
@@ -1564,12 +1519,14 @@ static long linereq_set_config(struct linereq *lr, void __user *ip)
	return 0;
}

static long linereq_ioctl_unlocked(struct file *file, unsigned int cmd,
static long linereq_ioctl(struct file *file, unsigned int cmd,
			  unsigned long arg)
{
	struct linereq *lr = file->private_data;
	void __user *ip = (void __user *)arg;

	guard(rwsem_read)(&lr->gdev->sem);

	if (!lr->gdev->chip)
		return -ENODEV;

@@ -1585,15 +1542,6 @@ static long linereq_ioctl_unlocked(struct file *file, unsigned int cmd,
	}
}

static long linereq_ioctl(struct file *file, unsigned int cmd,
			  unsigned long arg)
{
	struct linereq *lr = file->private_data;

	return call_ioctl_locked(file, cmd, arg, lr->gdev,
				 linereq_ioctl_unlocked);
}

#ifdef CONFIG_COMPAT
static long linereq_ioctl_compat(struct file *file, unsigned int cmd,
				 unsigned long arg)
@@ -1602,12 +1550,14 @@ static long linereq_ioctl_compat(struct file *file, unsigned int cmd,
}
#endif

static __poll_t linereq_poll_unlocked(struct file *file,
static __poll_t linereq_poll(struct file *file,
			     struct poll_table_struct *wait)
{
	struct linereq *lr = file->private_data;
	__poll_t events = 0;

	guard(rwsem_read)(&lr->gdev->sem);

	if (!lr->gdev->chip)
		return EPOLLHUP | EPOLLERR;

@@ -1620,15 +1570,7 @@ static __poll_t linereq_poll_unlocked(struct file *file,
	return events;
}

static __poll_t linereq_poll(struct file *file,
			     struct poll_table_struct *wait)
{
	struct linereq *lr = file->private_data;

	return call_poll_locked(file, wait, lr->gdev, linereq_poll_unlocked);
}

static ssize_t linereq_read_unlocked(struct file *file, char __user *buf,
static ssize_t linereq_read(struct file *file, char __user *buf,
			    size_t count, loff_t *f_ps)
{
	struct linereq *lr = file->private_data;
@@ -1636,6 +1578,8 @@ static ssize_t linereq_read_unlocked(struct file *file, char __user *buf,
	ssize_t bytes_read = 0;
	int ret;

	guard(rwsem_read)(&lr->gdev->sem);

	if (!lr->gdev->chip)
		return -ENODEV;

@@ -1677,15 +1621,6 @@ static ssize_t linereq_read_unlocked(struct file *file, char __user *buf,
	return bytes_read;
}

static ssize_t linereq_read(struct file *file, char __user *buf,
			    size_t count, loff_t *f_ps)
{
	struct linereq *lr = file->private_data;

	return call_read_locked(file, buf, count, f_ps, lr->gdev,
				linereq_read_unlocked);
}

static void linereq_free(struct linereq *lr)
{
	struct line *line;
@@ -1938,12 +1873,14 @@ struct lineevent_state {
	(GPIOEVENT_REQUEST_RISING_EDGE | \
	GPIOEVENT_REQUEST_FALLING_EDGE)

static __poll_t lineevent_poll_unlocked(struct file *file,
static __poll_t lineevent_poll(struct file *file,
			       struct poll_table_struct *wait)
{
	struct lineevent_state *le = file->private_data;
	__poll_t events = 0;

	guard(rwsem_read)(&le->gdev->sem);

	if (!le->gdev->chip)
		return EPOLLHUP | EPOLLERR;

@@ -1955,14 +1892,6 @@ static __poll_t lineevent_poll_unlocked(struct file *file,
	return events;
}

static __poll_t lineevent_poll(struct file *file,
			       struct poll_table_struct *wait)
{
	struct lineevent_state *le = file->private_data;

	return call_poll_locked(file, wait, le->gdev, lineevent_poll_unlocked);
}

static int lineevent_unregistered_notify(struct notifier_block *nb,
					 unsigned long action, void *data)
{
@@ -1979,7 +1908,7 @@ struct compat_gpioeevent_data {
	u32		id;
};

static ssize_t lineevent_read_unlocked(struct file *file, char __user *buf,
static ssize_t lineevent_read(struct file *file, char __user *buf,
			      size_t count, loff_t *f_ps)
{
	struct lineevent_state *le = file->private_data;
@@ -1988,6 +1917,8 @@ static ssize_t lineevent_read_unlocked(struct file *file, char __user *buf,
	ssize_t ge_size;
	int ret;

	guard(rwsem_read)(&le->gdev->sem);

	if (!le->gdev->chip)
		return -ENODEV;

@@ -2042,15 +1973,6 @@ static ssize_t lineevent_read_unlocked(struct file *file, char __user *buf,
	return bytes_read;
}

static ssize_t lineevent_read(struct file *file, char __user *buf,
			      size_t count, loff_t *f_ps)
{
	struct lineevent_state *le = file->private_data;

	return call_read_locked(file, buf, count, f_ps, le->gdev,
				lineevent_read_unlocked);
}

static void lineevent_free(struct lineevent_state *le)
{
	if (le->device_unregistered_nb.notifier_call)
@@ -2071,13 +1993,15 @@ static int lineevent_release(struct inode *inode, struct file *file)
	return 0;
}

static long lineevent_ioctl_unlocked(struct file *file, unsigned int cmd,
static long lineevent_ioctl(struct file *file, unsigned int cmd,
			    unsigned long arg)
{
	struct lineevent_state *le = file->private_data;
	void __user *ip = (void __user *)arg;
	struct gpiohandle_data ghd;

	guard(rwsem_read)(&le->gdev->sem);

	if (!le->gdev->chip)
		return -ENODEV;

@@ -2103,15 +2027,6 @@ static long lineevent_ioctl_unlocked(struct file *file, unsigned int cmd,
	return -EINVAL;
}

static long lineevent_ioctl(struct file *file, unsigned int cmd,
			    unsigned long arg)
{
	struct lineevent_state *le = file->private_data;

	return call_ioctl_locked(file, cmd, arg, le->gdev,
				 lineevent_ioctl_unlocked);
}

#ifdef CONFIG_COMPAT
static long lineevent_ioctl_compat(struct file *file, unsigned int cmd,
				   unsigned long arg)
@@ -2584,12 +2499,17 @@ static int lineinfo_unwatch(struct gpio_chardev_data *cdev, void __user *ip)
	return 0;
}

static long gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
/*
 * gpio_ioctl() - ioctl handler for the GPIO chardev
 */
static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct gpio_chardev_data *cdev = file->private_data;
	struct gpio_device *gdev = cdev->gdev;
	void __user *ip = (void __user *)arg;

	guard(rwsem_read)(&gdev->sem);

	/* We fail any subsequent ioctl():s when the chip is gone */
	if (!gdev->chip)
		return -ENODEV;
@@ -2621,17 +2541,6 @@ static long gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned lo
	}
}

/*
 * gpio_ioctl() - ioctl handler for the GPIO chardev
 */
static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct gpio_chardev_data *cdev = file->private_data;

	return call_ioctl_locked(file, cmd, arg, cdev->gdev,
				 gpio_ioctl_unlocked);
}

#ifdef CONFIG_COMPAT
static long gpio_ioctl_compat(struct file *file, unsigned int cmd,
			      unsigned long arg)
@@ -2679,12 +2588,14 @@ static int gpio_device_unregistered_notify(struct notifier_block *nb,
	return NOTIFY_OK;
}

static __poll_t lineinfo_watch_poll_unlocked(struct file *file,
static __poll_t lineinfo_watch_poll(struct file *file,
				    struct poll_table_struct *pollt)
{
	struct gpio_chardev_data *cdev = file->private_data;
	__poll_t events = 0;

	guard(rwsem_read)(&cdev->gdev->sem);

	if (!cdev->gdev->chip)
		return EPOLLHUP | EPOLLERR;

@@ -2697,16 +2608,7 @@ static __poll_t lineinfo_watch_poll_unlocked(struct file *file,
	return events;
}

static __poll_t lineinfo_watch_poll(struct file *file,
				    struct poll_table_struct *pollt)
{
	struct gpio_chardev_data *cdev = file->private_data;

	return call_poll_locked(file, pollt, cdev->gdev,
				lineinfo_watch_poll_unlocked);
}

static ssize_t lineinfo_watch_read_unlocked(struct file *file, char __user *buf,
static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
				   size_t count, loff_t *off)
{
	struct gpio_chardev_data *cdev = file->private_data;
@@ -2715,6 +2617,8 @@ static ssize_t lineinfo_watch_read_unlocked(struct file *file, char __user *buf,
	int ret;
	size_t event_size;

	guard(rwsem_read)(&cdev->gdev->sem);

	if (!cdev->gdev->chip)
		return -ENODEV;

@@ -2777,15 +2681,6 @@ static ssize_t lineinfo_watch_read_unlocked(struct file *file, char __user *buf,
	return bytes_read;
}

static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
				   size_t count, loff_t *off)
{
	struct gpio_chardev_data *cdev = file->private_data;

	return call_read_locked(file, buf, count, off, cdev->gdev,
				lineinfo_watch_read_unlocked);
}

/**
 * gpio_chrdev_open() - open the chardev for ioctl operations
 * @inode: inode for this chardev
@@ -2799,17 +2694,15 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
	struct gpio_chardev_data *cdev;
	int ret = -ENOMEM;

	down_read(&gdev->sem);
	guard(rwsem_read)(&gdev->sem);

	/* Fail on open if the backing gpiochip is gone */
	if (!gdev->chip) {
		ret = -ENODEV;
		goto out_unlock;
	}
	if (!gdev->chip)
		return -ENODEV;

	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
	if (!cdev)
		goto out_unlock;
		return -ENODEV;

	cdev->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL);
	if (!cdev->watched_lines)
@@ -2838,8 +2731,6 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
	if (ret)
		goto out_unregister_device_notifier;

	up_read(&gdev->sem);

	return ret;

out_unregister_device_notifier:
@@ -2853,8 +2744,6 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
	bitmap_free(cdev->watched_lines);
out_free_cdev:
	kfree(cdev);
out_unlock:
	up_read(&gdev->sem);
	return ret;
}