Commit 4e154159 authored by Bartosz Golaszewski's avatar Bartosz Golaszewski
Browse files

gpiolib: improve the robustness of watch/unwatch ioctl()



This makes the new ioctl() a bit more robust - we now check if a line
is already being watched and return -EBUSY if the user-space tries to
start watching it again. Same for unwatch - return -EBUSY if user-space
tries to unwatch a line that's not being watched.

Fixes: 51c1064e ("gpiolib: add new ioctl() for monitoring changes in line info")
Signed-off-by: default avatarBartosz Golaszewski <bgolaszewski@baylibre.com>
Reviewed-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent dc87f6dd
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -1227,6 +1227,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
	void __user *ip = (void __user *)arg;
	struct gpio_desc *desc;
	__u32 offset;
	int hwgpio;

	/* We fail any subsequent ioctl():s when the chip is gone */
	if (!gc)
@@ -1259,13 +1260,19 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		if (IS_ERR(desc))
			return PTR_ERR(desc);

		hwgpio = gpio_chip_hwgpio(desc);

		if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL &&
		    test_bit(hwgpio, priv->watched_lines))
			return -EBUSY;

		gpio_desc_to_lineinfo(desc, &lineinfo);

		if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
			return -EFAULT;

		if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL)
			set_bit(gpio_chip_hwgpio(desc), priv->watched_lines);
			set_bit(hwgpio, priv->watched_lines);

		return 0;
	} else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
@@ -1280,7 +1287,12 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		if (IS_ERR(desc))
			return PTR_ERR(desc);

		clear_bit(gpio_chip_hwgpio(desc), priv->watched_lines);
		hwgpio = gpio_chip_hwgpio(desc);

		if (!test_bit(hwgpio, priv->watched_lines))
			return -EBUSY;

		clear_bit(hwgpio, priv->watched_lines);
		return 0;
	}
	return -EINVAL;