* Re: [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1
@ 2020-06-23 7:26 kernel test robot
0 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2020-06-23 7:26 UTC (permalink / raw)
To: kbuild
[-- Attachment #1: Type: text/plain, Size: 2975 bytes --]
CC: kbuild-all(a)lists.01.org
In-Reply-To: <20200623040107.22270-17-warthog618@gmail.com>
References: <20200623040107.22270-17-warthog618@gmail.com>
TO: Kent Gibson <warthog618@gmail.com>
TO: linux-kernel(a)vger.kernel.org
TO: linux-gpio(a)vger.kernel.org
TO: bgolaszewski(a)baylibre.com
TO: linus.walleij(a)linaro.org
CC: Kent Gibson <warthog618@gmail.com>
Hi Kent,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on gpio/for-next]
[also build test WARNING on next-20200622]
[cannot apply to linux/master linus/master v5.8-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kent-Gibson/gpio-cdev-add-uAPI-V2/20200623-120634
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
:::::: branch date: 3 hours ago
:::::: commit date: 3 hours ago
config: nios2-randconfig-c023-20200623 (attached as .config)
compiler: nios2-linux-gcc (GCC) 9.3.0
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Julia Lawall <julia.lawall@lip6.fr>
coccinelle warnings: (new ones prefixed by >>)
>> drivers/gpio/gpiolib-cdev.c:891:13-17: ERROR: reference preceded by free on line 890
# https://github.com/0day-ci/linux/commit/f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
vim +891 drivers/gpio/gpiolib-cdev.c
f3b3ae8752adc5a Kent Gibson 2020-06-23 876
f3b3ae8752adc5a Kent Gibson 2020-06-23 877 static void line_free(struct line *line)
f3b3ae8752adc5a Kent Gibson 2020-06-23 878 {
f3b3ae8752adc5a Kent Gibson 2020-06-23 879 int i;
f3b3ae8752adc5a Kent Gibson 2020-06-23 880
f3b3ae8752adc5a Kent Gibson 2020-06-23 881 for (i = 0; i < line->num_descs; i++) {
f3b3ae8752adc5a Kent Gibson 2020-06-23 882 if (line->edets)
f3b3ae8752adc5a Kent Gibson 2020-06-23 883 edge_detector_stop(&line->edets[i]);
f3b3ae8752adc5a Kent Gibson 2020-06-23 884 if (line->descs[i])
f3b3ae8752adc5a Kent Gibson 2020-06-23 885 gpiod_free(line->descs[i]);
f3b3ae8752adc5a Kent Gibson 2020-06-23 886 }
f3b3ae8752adc5a Kent Gibson 2020-06-23 887 kfifo_free(&line->events);
f3b3ae8752adc5a Kent Gibson 2020-06-23 888 kfree(line->label);
f3b3ae8752adc5a Kent Gibson 2020-06-23 889 kfree(line->edets);
f3b3ae8752adc5a Kent Gibson 2020-06-23 @890 kfree(line);
f3b3ae8752adc5a Kent Gibson 2020-06-23 @891 put_device(&line->gdev->dev);
f3b3ae8752adc5a Kent Gibson 2020-06-23 892 }
f3b3ae8752adc5a Kent Gibson 2020-06-23 893
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 26841 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1
2020-06-23 17:44 ` Dan Carpenter
(?)
(?)
@ 2020-06-23 23:23 ` Kent Gibson
-1 siblings, 0 replies; 7+ messages in thread
From: Kent Gibson @ 2020-06-23 23:23 UTC (permalink / raw)
To: Dan Carpenter
Cc: kbuild, linux-kernel, linux-gpio, bgolaszewski, linus.walleij,
lkp, kbuild-all
On Tue, Jun 23, 2020 at 08:44:38PM +0300, Dan Carpenter wrote:
> [ The copy_to_user() overflow code is weird. Why do we need to do a
> atomic_read()? That suggests that there is a potential time of check
> time of use bug where we do:
>
It is weird, but you conveniently left out the guard comment:
/* must be after kfifo check so watch_abi_version is set */
> if (atomic_read(&gcdev->watch_abi_version) == 2) // <<-- time of check
> event_size = sizeof(struct gpioline_info_changed_v2);
>
For something to be in the fifo lineinfo_ensure_abi_version must've been
called. And the watch_abi_version can only be set once by
lineinfo_ensure_abi_version, so it cannot change between.
But point taken, I'll change the "time of use" condition to
if (event_size == sizeof(struct gpioline_info_changed_v2)) {
if (copy_to_user(buf + bytes_read, &event, event_size))
> ...
>
> if (atomic_read(&gcdev->watch_abi_version) == 2) { // <<-- time of use
> copy_to_user(blah, blah, event_size);
>
> If the value for "gcdev->watch_abi_version" changes between the time
> of check and the time of use then it can read beyond the end of the
> buffer.
>
> -- dan ]
>
> Hi Kent,
>
> Thank you for the patch! Perhaps something to improve:
>
> url: https://github.com/0day-ci/linux/commits/Kent-Gibson/gpio-cdev-add-uAPI-V2/20200623-120634
> base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
> config: openrisc-randconfig-m031-20200623 (attached as .config)
> compiler: or1k-linux-gcc (GCC) 9.3.0
>
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
> Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
>
> smatch warnings:
> drivers/gpio/gpiolib-cdev.c:891 line_free() error: dereferencing freed memory 'line'
> drivers/gpio/gpiolib-cdev.c:949 line_create() warn: possible memory leak of 'line'
> drivers/gpio/gpiolib-cdev.c:1860 lineinfo_watch_read() error: copy_to_user() '&event_v1' too small (104 vs 168)
>
> # https://github.com/0day-ci/linux/commit/f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
> git remote add linux-review https://github.com/0day-ci/linux
> git remote update linux-review
> git checkout f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
> vim +/line +891 drivers/gpio/gpiolib-cdev.c
>
> f3b3ae8752adc5 Kent Gibson 2020-06-23 877 static void line_free(struct line *line)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 878 {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 879 int i;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 880
> f3b3ae8752adc5 Kent Gibson 2020-06-23 881 for (i = 0; i < line->num_descs; i++) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 882 if (line->edets)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 883 edge_detector_stop(&line->edets[i]);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 884 if (line->descs[i])
> f3b3ae8752adc5 Kent Gibson 2020-06-23 885 gpiod_free(line->descs[i]);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 886 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 887 kfifo_free(&line->events);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 888 kfree(line->label);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 889 kfree(line->edets);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 890 kfree(line);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 @891 put_device(&line->gdev->dev);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 892 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 893
> f3b3ae8752adc5 Kent Gibson 2020-06-23 894 static int line_release(struct inode *inode, struct file *file)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 895 {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 896 struct line *line = file->private_data;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 897
> f3b3ae8752adc5 Kent Gibson 2020-06-23 898 line_free(line);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 899 return 0;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 900 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 901
> f3b3ae8752adc5 Kent Gibson 2020-06-23 902 static const struct file_operations line_fileops = {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 903 .release = line_release,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 904 .read = line_read,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 905 .poll = line_poll,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 906 .owner = THIS_MODULE,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 907 .llseek = noop_llseek,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 908 .unlocked_ioctl = line_ioctl,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 909 #ifdef CONFIG_COMPAT
> f3b3ae8752adc5 Kent Gibson 2020-06-23 910 .compat_ioctl = line_ioctl_compat,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 911 #endif
> f3b3ae8752adc5 Kent Gibson 2020-06-23 912 };
> f3b3ae8752adc5 Kent Gibson 2020-06-23 913
> f3b3ae8752adc5 Kent Gibson 2020-06-23 914 static int line_create(struct gpio_device *gdev, void __user *ip)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 915 {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 916 struct gpioline_request linereq;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 917 struct line *line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 918 struct file *file;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 919 int fd, i, ret, size;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 920 struct gpioline_config *lc;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 921 unsigned long *vals;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 922
> f3b3ae8752adc5 Kent Gibson 2020-06-23 923 if (copy_from_user(&linereq, ip, sizeof(linereq)))
> f3b3ae8752adc5 Kent Gibson 2020-06-23 924 return -EFAULT;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 925 if ((linereq.num_lines == 0) || (linereq.num_lines > GPIOLINES_MAX))
> f3b3ae8752adc5 Kent Gibson 2020-06-23 926 return -EINVAL;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 927
> f3b3ae8752adc5 Kent Gibson 2020-06-23 928 if (padding_not_zeroed(linereq.padding, GPIOLINE_REQUEST_PAD_SIZE))
> f3b3ae8752adc5 Kent Gibson 2020-06-23 929 return -EINVAL;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 930
> f3b3ae8752adc5 Kent Gibson 2020-06-23 931 lc = &linereq.config;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 932 ret = gpioline_config_validate(lc);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 933 if (ret)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 934 return ret;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 935
> f3b3ae8752adc5 Kent Gibson 2020-06-23 936 /* event_buffer_size only valid with edge_detection */
> f3b3ae8752adc5 Kent Gibson 2020-06-23 937 if ((linereq.event_buffer_size) &&
> f3b3ae8752adc5 Kent Gibson 2020-06-23 938 !(linereq.config.flags & GPIOLINE_FLAG_V2_EDGE_DETECTION))
> f3b3ae8752adc5 Kent Gibson 2020-06-23 939 return -EINVAL;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 940
> f3b3ae8752adc5 Kent Gibson 2020-06-23 941 line = kzalloc(struct_size(line, descs, linereq.num_lines),
> f3b3ae8752adc5 Kent Gibson 2020-06-23 942 GFP_KERNEL);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 943 if (!line)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 944 return -ENOMEM;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 945
> f3b3ae8752adc5 Kent Gibson 2020-06-23 946 line->edets = kcalloc(linereq.num_lines, sizeof(*line->edets),
> f3b3ae8752adc5 Kent Gibson 2020-06-23 947 GFP_KERNEL);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 948 if (!line->edets)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 @949 return -ENOMEM;
> ^^^^^^^^^^^^^^^
> kfree(line) before returning.
>
Yeah, that is bad. Good pickup - it should be a goto out_free_line like
the one below for line->label.
Cheers,
Kent.
> f3b3ae8752adc5 Kent Gibson 2020-06-23 950
> f3b3ae8752adc5 Kent Gibson 2020-06-23 951 for (i = 0; i < linereq.num_lines; i++)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 952 line->edets[i].line = line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 953
> f3b3ae8752adc5 Kent Gibson 2020-06-23 954 line->gdev = gdev;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 955 get_device(&gdev->dev);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 956
> f3b3ae8752adc5 Kent Gibson 2020-06-23 957 /* Make sure this is terminated */
> f3b3ae8752adc5 Kent Gibson 2020-06-23 958 linereq.consumer[sizeof(linereq.consumer)-1] = '\0';
> f3b3ae8752adc5 Kent Gibson 2020-06-23 959 if (strlen(linereq.consumer)) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 960 line->label = kstrdup(linereq.consumer, GFP_KERNEL);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 961 if (!line->label) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 962 ret = -ENOMEM;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 963 goto out_free_line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 964 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 965 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 966
> f3b3ae8752adc5 Kent Gibson 2020-06-23 967 mutex_init(&line->config_mutex);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 968 init_waitqueue_head(&line->wait);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 969 if (lc->edge_detection) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 970 size = linereq.event_buffer_size;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 971
> f3b3ae8752adc5 Kent Gibson 2020-06-23 972 if (size > GPIOLINES_MAX*16)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 973 size = GPIOLINES_MAX*16;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 974 else if (size == 0)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 975 size = linereq.num_lines*16;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 976
> f3b3ae8752adc5 Kent Gibson 2020-06-23 977 ret = kfifo_alloc(&line->events, size, GFP_KERNEL);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 978 if (ret)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 979 goto out_free_line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 980
> f3b3ae8752adc5 Kent Gibson 2020-06-23 981 line->edge_detection = lc->edge_detection;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 982 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 983
> f3b3ae8752adc5 Kent Gibson 2020-06-23 984 atomic_set(&line->seqno, 0);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 985 line->num_descs = linereq.num_lines;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 986 vals = (unsigned long *)lc->values.bitmap;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 987
> f3b3ae8752adc5 Kent Gibson 2020-06-23 988 /* Request each GPIO */
> f3b3ae8752adc5 Kent Gibson 2020-06-23 989 for (i = 0; i < linereq.num_lines; i++) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 990 u32 offset = linereq.offsets[i];
> f3b3ae8752adc5 Kent Gibson 2020-06-23 991 struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 992
> f3b3ae8752adc5 Kent Gibson 2020-06-23 993 if (IS_ERR(desc)) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 994 ret = PTR_ERR(desc);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 995 goto out_free_line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 996 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 997
> f3b3ae8752adc5 Kent Gibson 2020-06-23 998 ret = gpiod_request(desc, line->label);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 999 if (ret)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1000 goto out_free_line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1001
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1002 line->descs[i] = desc;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1003 gpioline_config_to_desc_flags(lc, &desc->flags);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1004
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1005 ret = gpiod_set_transitory(desc, false);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1006 if (ret < 0)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1007 goto out_free_line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1008
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1009 /*
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1010 * Lines have to be requested explicitly for input
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1011 * or output, else the line will be treated "as is".
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1012 */
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1013 if (lc->flags & GPIOLINE_FLAG_V2_DIRECTION) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1014 if (lc->direction == GPIOLINE_DIRECTION_OUTPUT) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1015 int val = test_bit(i, vals);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1016
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1017 ret = gpiod_direction_output(desc, val);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1018 if (ret)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1019 goto out_free_line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1020 } else {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1021 ret = gpiod_direction_input(desc);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1022 if (ret)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1023 goto out_free_line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1024 ret = edge_detector_setup(&line->edets[i], lc);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1025 if (ret)
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1026 goto out_free_line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1027 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1028 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1029
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1030 atomic_notifier_call_chain(&desc->gdev->notifier,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1031 GPIOLINE_CHANGED_REQUESTED, desc);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1032
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1033 dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1034 offset);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1035 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1036
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1037 fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1038 if (fd < 0) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1039 ret = fd;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1040 goto out_free_line;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1041 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1042
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1043 file = anon_inode_getfile("gpio-line",
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1044 &line_fileops,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1045 line,
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1046 O_RDONLY | O_CLOEXEC);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1047 if (IS_ERR(file)) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1048 ret = PTR_ERR(file);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1049 goto out_put_unused_fd;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1050 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1051
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1052 linereq.fd = fd;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1053 if (copy_to_user(ip, &linereq, sizeof(linereq))) {
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1054 /*
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1055 * fput() will trigger the release() callback, so do not go onto
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1056 * the regular error cleanup path here.
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1057 */
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1058 fput(file);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1059 put_unused_fd(fd);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1060 return -EFAULT;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1061 }
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1062
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1063 fd_install(fd, file);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1064
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1065 dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1066 line->num_descs);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1067
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1068 return 0;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1069
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1070 out_put_unused_fd:
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1071 put_unused_fd(fd);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1072 out_free_line:
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1073 line_free(line);
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1074 return ret;
> f3b3ae8752adc5 Kent Gibson 2020-06-23 1075 }
>
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1
2020-06-23 4:01 ` [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1 Kent Gibson
2020-06-23 17:44 ` Dan Carpenter
@ 2020-06-23 17:44 ` Dan Carpenter
0 siblings, 0 replies; 7+ messages in thread
From: Dan Carpenter @ 2020-06-23 17:44 UTC (permalink / raw)
To: kbuild, Kent Gibson, linux-kernel, linux-gpio, bgolaszewski,
linus.walleij
Cc: lkp, kbuild-all, Kent Gibson
[-- Attachment #1: Type: text/plain, Size: 15322 bytes --]
[ The copy_to_user() overflow code is weird. Why do we need to do a
atomic_read()? That suggests that there is a potential time of check
time of use bug where we do:
if (atomic_read(&gcdev->watch_abi_version) == 2) // <<-- time of check
event_size = sizeof(struct gpioline_info_changed_v2);
...
if (atomic_read(&gcdev->watch_abi_version) == 2) { // <<-- time of use
copy_to_user(blah, blah, event_size);
If the value for "gcdev->watch_abi_version" changes between the time
of check and the time of use then it can read beyond the end of the
buffer.
-- dan ]
Hi Kent,
Thank you for the patch! Perhaps something to improve:
url: https://github.com/0day-ci/linux/commits/Kent-Gibson/gpio-cdev-add-uAPI-V2/20200623-120634
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
config: openrisc-randconfig-m031-20200623 (attached as .config)
compiler: or1k-linux-gcc (GCC) 9.3.0
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
smatch warnings:
drivers/gpio/gpiolib-cdev.c:891 line_free() error: dereferencing freed memory 'line'
drivers/gpio/gpiolib-cdev.c:949 line_create() warn: possible memory leak of 'line'
drivers/gpio/gpiolib-cdev.c:1860 lineinfo_watch_read() error: copy_to_user() '&event_v1' too small (104 vs 168)
# https://github.com/0day-ci/linux/commit/f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
vim +/line +891 drivers/gpio/gpiolib-cdev.c
f3b3ae8752adc5 Kent Gibson 2020-06-23 877 static void line_free(struct line *line)
f3b3ae8752adc5 Kent Gibson 2020-06-23 878 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 879 int i;
f3b3ae8752adc5 Kent Gibson 2020-06-23 880
f3b3ae8752adc5 Kent Gibson 2020-06-23 881 for (i = 0; i < line->num_descs; i++) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 882 if (line->edets)
f3b3ae8752adc5 Kent Gibson 2020-06-23 883 edge_detector_stop(&line->edets[i]);
f3b3ae8752adc5 Kent Gibson 2020-06-23 884 if (line->descs[i])
f3b3ae8752adc5 Kent Gibson 2020-06-23 885 gpiod_free(line->descs[i]);
f3b3ae8752adc5 Kent Gibson 2020-06-23 886 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 887 kfifo_free(&line->events);
f3b3ae8752adc5 Kent Gibson 2020-06-23 888 kfree(line->label);
f3b3ae8752adc5 Kent Gibson 2020-06-23 889 kfree(line->edets);
f3b3ae8752adc5 Kent Gibson 2020-06-23 890 kfree(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 @891 put_device(&line->gdev->dev);
f3b3ae8752adc5 Kent Gibson 2020-06-23 892 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 893
f3b3ae8752adc5 Kent Gibson 2020-06-23 894 static int line_release(struct inode *inode, struct file *file)
f3b3ae8752adc5 Kent Gibson 2020-06-23 895 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 896 struct line *line = file->private_data;
f3b3ae8752adc5 Kent Gibson 2020-06-23 897
f3b3ae8752adc5 Kent Gibson 2020-06-23 898 line_free(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 899 return 0;
f3b3ae8752adc5 Kent Gibson 2020-06-23 900 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 901
f3b3ae8752adc5 Kent Gibson 2020-06-23 902 static const struct file_operations line_fileops = {
f3b3ae8752adc5 Kent Gibson 2020-06-23 903 .release = line_release,
f3b3ae8752adc5 Kent Gibson 2020-06-23 904 .read = line_read,
f3b3ae8752adc5 Kent Gibson 2020-06-23 905 .poll = line_poll,
f3b3ae8752adc5 Kent Gibson 2020-06-23 906 .owner = THIS_MODULE,
f3b3ae8752adc5 Kent Gibson 2020-06-23 907 .llseek = noop_llseek,
f3b3ae8752adc5 Kent Gibson 2020-06-23 908 .unlocked_ioctl = line_ioctl,
f3b3ae8752adc5 Kent Gibson 2020-06-23 909 #ifdef CONFIG_COMPAT
f3b3ae8752adc5 Kent Gibson 2020-06-23 910 .compat_ioctl = line_ioctl_compat,
f3b3ae8752adc5 Kent Gibson 2020-06-23 911 #endif
f3b3ae8752adc5 Kent Gibson 2020-06-23 912 };
f3b3ae8752adc5 Kent Gibson 2020-06-23 913
f3b3ae8752adc5 Kent Gibson 2020-06-23 914 static int line_create(struct gpio_device *gdev, void __user *ip)
f3b3ae8752adc5 Kent Gibson 2020-06-23 915 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 916 struct gpioline_request linereq;
f3b3ae8752adc5 Kent Gibson 2020-06-23 917 struct line *line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 918 struct file *file;
f3b3ae8752adc5 Kent Gibson 2020-06-23 919 int fd, i, ret, size;
f3b3ae8752adc5 Kent Gibson 2020-06-23 920 struct gpioline_config *lc;
f3b3ae8752adc5 Kent Gibson 2020-06-23 921 unsigned long *vals;
f3b3ae8752adc5 Kent Gibson 2020-06-23 922
f3b3ae8752adc5 Kent Gibson 2020-06-23 923 if (copy_from_user(&linereq, ip, sizeof(linereq)))
f3b3ae8752adc5 Kent Gibson 2020-06-23 924 return -EFAULT;
f3b3ae8752adc5 Kent Gibson 2020-06-23 925 if ((linereq.num_lines == 0) || (linereq.num_lines > GPIOLINES_MAX))
f3b3ae8752adc5 Kent Gibson 2020-06-23 926 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 927
f3b3ae8752adc5 Kent Gibson 2020-06-23 928 if (padding_not_zeroed(linereq.padding, GPIOLINE_REQUEST_PAD_SIZE))
f3b3ae8752adc5 Kent Gibson 2020-06-23 929 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 930
f3b3ae8752adc5 Kent Gibson 2020-06-23 931 lc = &linereq.config;
f3b3ae8752adc5 Kent Gibson 2020-06-23 932 ret = gpioline_config_validate(lc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 933 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 934 return ret;
f3b3ae8752adc5 Kent Gibson 2020-06-23 935
f3b3ae8752adc5 Kent Gibson 2020-06-23 936 /* event_buffer_size only valid with edge_detection */
f3b3ae8752adc5 Kent Gibson 2020-06-23 937 if ((linereq.event_buffer_size) &&
f3b3ae8752adc5 Kent Gibson 2020-06-23 938 !(linereq.config.flags & GPIOLINE_FLAG_V2_EDGE_DETECTION))
f3b3ae8752adc5 Kent Gibson 2020-06-23 939 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 940
f3b3ae8752adc5 Kent Gibson 2020-06-23 941 line = kzalloc(struct_size(line, descs, linereq.num_lines),
f3b3ae8752adc5 Kent Gibson 2020-06-23 942 GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 943 if (!line)
f3b3ae8752adc5 Kent Gibson 2020-06-23 944 return -ENOMEM;
f3b3ae8752adc5 Kent Gibson 2020-06-23 945
f3b3ae8752adc5 Kent Gibson 2020-06-23 946 line->edets = kcalloc(linereq.num_lines, sizeof(*line->edets),
f3b3ae8752adc5 Kent Gibson 2020-06-23 947 GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 948 if (!line->edets)
f3b3ae8752adc5 Kent Gibson 2020-06-23 @949 return -ENOMEM;
^^^^^^^^^^^^^^^
kfree(line) before returning.
f3b3ae8752adc5 Kent Gibson 2020-06-23 950
f3b3ae8752adc5 Kent Gibson 2020-06-23 951 for (i = 0; i < linereq.num_lines; i++)
f3b3ae8752adc5 Kent Gibson 2020-06-23 952 line->edets[i].line = line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 953
f3b3ae8752adc5 Kent Gibson 2020-06-23 954 line->gdev = gdev;
f3b3ae8752adc5 Kent Gibson 2020-06-23 955 get_device(&gdev->dev);
f3b3ae8752adc5 Kent Gibson 2020-06-23 956
f3b3ae8752adc5 Kent Gibson 2020-06-23 957 /* Make sure this is terminated */
f3b3ae8752adc5 Kent Gibson 2020-06-23 958 linereq.consumer[sizeof(linereq.consumer)-1] = '\0';
f3b3ae8752adc5 Kent Gibson 2020-06-23 959 if (strlen(linereq.consumer)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 960 line->label = kstrdup(linereq.consumer, GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 961 if (!line->label) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 962 ret = -ENOMEM;
f3b3ae8752adc5 Kent Gibson 2020-06-23 963 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 964 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 965 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 966
f3b3ae8752adc5 Kent Gibson 2020-06-23 967 mutex_init(&line->config_mutex);
f3b3ae8752adc5 Kent Gibson 2020-06-23 968 init_waitqueue_head(&line->wait);
f3b3ae8752adc5 Kent Gibson 2020-06-23 969 if (lc->edge_detection) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 970 size = linereq.event_buffer_size;
f3b3ae8752adc5 Kent Gibson 2020-06-23 971
f3b3ae8752adc5 Kent Gibson 2020-06-23 972 if (size > GPIOLINES_MAX*16)
f3b3ae8752adc5 Kent Gibson 2020-06-23 973 size = GPIOLINES_MAX*16;
f3b3ae8752adc5 Kent Gibson 2020-06-23 974 else if (size == 0)
f3b3ae8752adc5 Kent Gibson 2020-06-23 975 size = linereq.num_lines*16;
f3b3ae8752adc5 Kent Gibson 2020-06-23 976
f3b3ae8752adc5 Kent Gibson 2020-06-23 977 ret = kfifo_alloc(&line->events, size, GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 978 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 979 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 980
f3b3ae8752adc5 Kent Gibson 2020-06-23 981 line->edge_detection = lc->edge_detection;
f3b3ae8752adc5 Kent Gibson 2020-06-23 982 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 983
f3b3ae8752adc5 Kent Gibson 2020-06-23 984 atomic_set(&line->seqno, 0);
f3b3ae8752adc5 Kent Gibson 2020-06-23 985 line->num_descs = linereq.num_lines;
f3b3ae8752adc5 Kent Gibson 2020-06-23 986 vals = (unsigned long *)lc->values.bitmap;
f3b3ae8752adc5 Kent Gibson 2020-06-23 987
f3b3ae8752adc5 Kent Gibson 2020-06-23 988 /* Request each GPIO */
f3b3ae8752adc5 Kent Gibson 2020-06-23 989 for (i = 0; i < linereq.num_lines; i++) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 990 u32 offset = linereq.offsets[i];
f3b3ae8752adc5 Kent Gibson 2020-06-23 991 struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
f3b3ae8752adc5 Kent Gibson 2020-06-23 992
f3b3ae8752adc5 Kent Gibson 2020-06-23 993 if (IS_ERR(desc)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 994 ret = PTR_ERR(desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 995 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 996 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 997
f3b3ae8752adc5 Kent Gibson 2020-06-23 998 ret = gpiod_request(desc, line->label);
f3b3ae8752adc5 Kent Gibson 2020-06-23 999 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1000 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1001
f3b3ae8752adc5 Kent Gibson 2020-06-23 1002 line->descs[i] = desc;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1003 gpioline_config_to_desc_flags(lc, &desc->flags);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1004
f3b3ae8752adc5 Kent Gibson 2020-06-23 1005 ret = gpiod_set_transitory(desc, false);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1006 if (ret < 0)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1007 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1008
f3b3ae8752adc5 Kent Gibson 2020-06-23 1009 /*
f3b3ae8752adc5 Kent Gibson 2020-06-23 1010 * Lines have to be requested explicitly for input
f3b3ae8752adc5 Kent Gibson 2020-06-23 1011 * or output, else the line will be treated "as is".
f3b3ae8752adc5 Kent Gibson 2020-06-23 1012 */
f3b3ae8752adc5 Kent Gibson 2020-06-23 1013 if (lc->flags & GPIOLINE_FLAG_V2_DIRECTION) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1014 if (lc->direction == GPIOLINE_DIRECTION_OUTPUT) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1015 int val = test_bit(i, vals);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1016
f3b3ae8752adc5 Kent Gibson 2020-06-23 1017 ret = gpiod_direction_output(desc, val);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1018 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1019 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1020 } else {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1021 ret = gpiod_direction_input(desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1022 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1023 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1024 ret = edge_detector_setup(&line->edets[i], lc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1025 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1026 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1027 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1028 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1029
f3b3ae8752adc5 Kent Gibson 2020-06-23 1030 atomic_notifier_call_chain(&desc->gdev->notifier,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1031 GPIOLINE_CHANGED_REQUESTED, desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1032
f3b3ae8752adc5 Kent Gibson 2020-06-23 1033 dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1034 offset);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1035 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1036
f3b3ae8752adc5 Kent Gibson 2020-06-23 1037 fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1038 if (fd < 0) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1039 ret = fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1040 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1041 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1042
f3b3ae8752adc5 Kent Gibson 2020-06-23 1043 file = anon_inode_getfile("gpio-line",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1044 &line_fileops,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1045 line,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1046 O_RDONLY | O_CLOEXEC);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1047 if (IS_ERR(file)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1048 ret = PTR_ERR(file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1049 goto out_put_unused_fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1050 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1051
f3b3ae8752adc5 Kent Gibson 2020-06-23 1052 linereq.fd = fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1053 if (copy_to_user(ip, &linereq, sizeof(linereq))) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1054 /*
f3b3ae8752adc5 Kent Gibson 2020-06-23 1055 * fput() will trigger the release() callback, so do not go onto
f3b3ae8752adc5 Kent Gibson 2020-06-23 1056 * the regular error cleanup path here.
f3b3ae8752adc5 Kent Gibson 2020-06-23 1057 */
f3b3ae8752adc5 Kent Gibson 2020-06-23 1058 fput(file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1059 put_unused_fd(fd);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1060 return -EFAULT;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1061 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1062
f3b3ae8752adc5 Kent Gibson 2020-06-23 1063 fd_install(fd, file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1064
f3b3ae8752adc5 Kent Gibson 2020-06-23 1065 dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1066 line->num_descs);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1067
f3b3ae8752adc5 Kent Gibson 2020-06-23 1068 return 0;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1069
f3b3ae8752adc5 Kent Gibson 2020-06-23 1070 out_put_unused_fd:
f3b3ae8752adc5 Kent Gibson 2020-06-23 1071 put_unused_fd(fd);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1072 out_free_line:
f3b3ae8752adc5 Kent Gibson 2020-06-23 1073 line_free(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1074 return ret;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1075 }
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 25304 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1
@ 2020-06-23 17:44 ` Dan Carpenter
0 siblings, 0 replies; 7+ messages in thread
From: Dan Carpenter @ 2020-06-23 17:44 UTC (permalink / raw)
To: kbuild
[-- Attachment #1: Type: text/plain, Size: 15572 bytes --]
[ The copy_to_user() overflow code is weird. Why do we need to do a
atomic_read()? That suggests that there is a potential time of check
time of use bug where we do:
if (atomic_read(&gcdev->watch_abi_version) == 2) // <<-- time of check
event_size = sizeof(struct gpioline_info_changed_v2);
...
if (atomic_read(&gcdev->watch_abi_version) == 2) { // <<-- time of use
copy_to_user(blah, blah, event_size);
If the value for "gcdev->watch_abi_version" changes between the time
of check and the time of use then it can read beyond the end of the
buffer.
-- dan ]
Hi Kent,
Thank you for the patch! Perhaps something to improve:
url: https://github.com/0day-ci/linux/commits/Kent-Gibson/gpio-cdev-add-uAPI-V2/20200623-120634
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
config: openrisc-randconfig-m031-20200623 (attached as .config)
compiler: or1k-linux-gcc (GCC) 9.3.0
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
smatch warnings:
drivers/gpio/gpiolib-cdev.c:891 line_free() error: dereferencing freed memory 'line'
drivers/gpio/gpiolib-cdev.c:949 line_create() warn: possible memory leak of 'line'
drivers/gpio/gpiolib-cdev.c:1860 lineinfo_watch_read() error: copy_to_user() '&event_v1' too small (104 vs 168)
# https://github.com/0day-ci/linux/commit/f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
vim +/line +891 drivers/gpio/gpiolib-cdev.c
f3b3ae8752adc5 Kent Gibson 2020-06-23 877 static void line_free(struct line *line)
f3b3ae8752adc5 Kent Gibson 2020-06-23 878 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 879 int i;
f3b3ae8752adc5 Kent Gibson 2020-06-23 880
f3b3ae8752adc5 Kent Gibson 2020-06-23 881 for (i = 0; i < line->num_descs; i++) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 882 if (line->edets)
f3b3ae8752adc5 Kent Gibson 2020-06-23 883 edge_detector_stop(&line->edets[i]);
f3b3ae8752adc5 Kent Gibson 2020-06-23 884 if (line->descs[i])
f3b3ae8752adc5 Kent Gibson 2020-06-23 885 gpiod_free(line->descs[i]);
f3b3ae8752adc5 Kent Gibson 2020-06-23 886 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 887 kfifo_free(&line->events);
f3b3ae8752adc5 Kent Gibson 2020-06-23 888 kfree(line->label);
f3b3ae8752adc5 Kent Gibson 2020-06-23 889 kfree(line->edets);
f3b3ae8752adc5 Kent Gibson 2020-06-23 890 kfree(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 @891 put_device(&line->gdev->dev);
f3b3ae8752adc5 Kent Gibson 2020-06-23 892 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 893
f3b3ae8752adc5 Kent Gibson 2020-06-23 894 static int line_release(struct inode *inode, struct file *file)
f3b3ae8752adc5 Kent Gibson 2020-06-23 895 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 896 struct line *line = file->private_data;
f3b3ae8752adc5 Kent Gibson 2020-06-23 897
f3b3ae8752adc5 Kent Gibson 2020-06-23 898 line_free(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 899 return 0;
f3b3ae8752adc5 Kent Gibson 2020-06-23 900 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 901
f3b3ae8752adc5 Kent Gibson 2020-06-23 902 static const struct file_operations line_fileops = {
f3b3ae8752adc5 Kent Gibson 2020-06-23 903 .release = line_release,
f3b3ae8752adc5 Kent Gibson 2020-06-23 904 .read = line_read,
f3b3ae8752adc5 Kent Gibson 2020-06-23 905 .poll = line_poll,
f3b3ae8752adc5 Kent Gibson 2020-06-23 906 .owner = THIS_MODULE,
f3b3ae8752adc5 Kent Gibson 2020-06-23 907 .llseek = noop_llseek,
f3b3ae8752adc5 Kent Gibson 2020-06-23 908 .unlocked_ioctl = line_ioctl,
f3b3ae8752adc5 Kent Gibson 2020-06-23 909 #ifdef CONFIG_COMPAT
f3b3ae8752adc5 Kent Gibson 2020-06-23 910 .compat_ioctl = line_ioctl_compat,
f3b3ae8752adc5 Kent Gibson 2020-06-23 911 #endif
f3b3ae8752adc5 Kent Gibson 2020-06-23 912 };
f3b3ae8752adc5 Kent Gibson 2020-06-23 913
f3b3ae8752adc5 Kent Gibson 2020-06-23 914 static int line_create(struct gpio_device *gdev, void __user *ip)
f3b3ae8752adc5 Kent Gibson 2020-06-23 915 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 916 struct gpioline_request linereq;
f3b3ae8752adc5 Kent Gibson 2020-06-23 917 struct line *line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 918 struct file *file;
f3b3ae8752adc5 Kent Gibson 2020-06-23 919 int fd, i, ret, size;
f3b3ae8752adc5 Kent Gibson 2020-06-23 920 struct gpioline_config *lc;
f3b3ae8752adc5 Kent Gibson 2020-06-23 921 unsigned long *vals;
f3b3ae8752adc5 Kent Gibson 2020-06-23 922
f3b3ae8752adc5 Kent Gibson 2020-06-23 923 if (copy_from_user(&linereq, ip, sizeof(linereq)))
f3b3ae8752adc5 Kent Gibson 2020-06-23 924 return -EFAULT;
f3b3ae8752adc5 Kent Gibson 2020-06-23 925 if ((linereq.num_lines == 0) || (linereq.num_lines > GPIOLINES_MAX))
f3b3ae8752adc5 Kent Gibson 2020-06-23 926 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 927
f3b3ae8752adc5 Kent Gibson 2020-06-23 928 if (padding_not_zeroed(linereq.padding, GPIOLINE_REQUEST_PAD_SIZE))
f3b3ae8752adc5 Kent Gibson 2020-06-23 929 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 930
f3b3ae8752adc5 Kent Gibson 2020-06-23 931 lc = &linereq.config;
f3b3ae8752adc5 Kent Gibson 2020-06-23 932 ret = gpioline_config_validate(lc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 933 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 934 return ret;
f3b3ae8752adc5 Kent Gibson 2020-06-23 935
f3b3ae8752adc5 Kent Gibson 2020-06-23 936 /* event_buffer_size only valid with edge_detection */
f3b3ae8752adc5 Kent Gibson 2020-06-23 937 if ((linereq.event_buffer_size) &&
f3b3ae8752adc5 Kent Gibson 2020-06-23 938 !(linereq.config.flags & GPIOLINE_FLAG_V2_EDGE_DETECTION))
f3b3ae8752adc5 Kent Gibson 2020-06-23 939 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 940
f3b3ae8752adc5 Kent Gibson 2020-06-23 941 line = kzalloc(struct_size(line, descs, linereq.num_lines),
f3b3ae8752adc5 Kent Gibson 2020-06-23 942 GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 943 if (!line)
f3b3ae8752adc5 Kent Gibson 2020-06-23 944 return -ENOMEM;
f3b3ae8752adc5 Kent Gibson 2020-06-23 945
f3b3ae8752adc5 Kent Gibson 2020-06-23 946 line->edets = kcalloc(linereq.num_lines, sizeof(*line->edets),
f3b3ae8752adc5 Kent Gibson 2020-06-23 947 GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 948 if (!line->edets)
f3b3ae8752adc5 Kent Gibson 2020-06-23 @949 return -ENOMEM;
^^^^^^^^^^^^^^^
kfree(line) before returning.
f3b3ae8752adc5 Kent Gibson 2020-06-23 950
f3b3ae8752adc5 Kent Gibson 2020-06-23 951 for (i = 0; i < linereq.num_lines; i++)
f3b3ae8752adc5 Kent Gibson 2020-06-23 952 line->edets[i].line = line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 953
f3b3ae8752adc5 Kent Gibson 2020-06-23 954 line->gdev = gdev;
f3b3ae8752adc5 Kent Gibson 2020-06-23 955 get_device(&gdev->dev);
f3b3ae8752adc5 Kent Gibson 2020-06-23 956
f3b3ae8752adc5 Kent Gibson 2020-06-23 957 /* Make sure this is terminated */
f3b3ae8752adc5 Kent Gibson 2020-06-23 958 linereq.consumer[sizeof(linereq.consumer)-1] = '\0';
f3b3ae8752adc5 Kent Gibson 2020-06-23 959 if (strlen(linereq.consumer)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 960 line->label = kstrdup(linereq.consumer, GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 961 if (!line->label) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 962 ret = -ENOMEM;
f3b3ae8752adc5 Kent Gibson 2020-06-23 963 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 964 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 965 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 966
f3b3ae8752adc5 Kent Gibson 2020-06-23 967 mutex_init(&line->config_mutex);
f3b3ae8752adc5 Kent Gibson 2020-06-23 968 init_waitqueue_head(&line->wait);
f3b3ae8752adc5 Kent Gibson 2020-06-23 969 if (lc->edge_detection) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 970 size = linereq.event_buffer_size;
f3b3ae8752adc5 Kent Gibson 2020-06-23 971
f3b3ae8752adc5 Kent Gibson 2020-06-23 972 if (size > GPIOLINES_MAX*16)
f3b3ae8752adc5 Kent Gibson 2020-06-23 973 size = GPIOLINES_MAX*16;
f3b3ae8752adc5 Kent Gibson 2020-06-23 974 else if (size == 0)
f3b3ae8752adc5 Kent Gibson 2020-06-23 975 size = linereq.num_lines*16;
f3b3ae8752adc5 Kent Gibson 2020-06-23 976
f3b3ae8752adc5 Kent Gibson 2020-06-23 977 ret = kfifo_alloc(&line->events, size, GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 978 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 979 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 980
f3b3ae8752adc5 Kent Gibson 2020-06-23 981 line->edge_detection = lc->edge_detection;
f3b3ae8752adc5 Kent Gibson 2020-06-23 982 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 983
f3b3ae8752adc5 Kent Gibson 2020-06-23 984 atomic_set(&line->seqno, 0);
f3b3ae8752adc5 Kent Gibson 2020-06-23 985 line->num_descs = linereq.num_lines;
f3b3ae8752adc5 Kent Gibson 2020-06-23 986 vals = (unsigned long *)lc->values.bitmap;
f3b3ae8752adc5 Kent Gibson 2020-06-23 987
f3b3ae8752adc5 Kent Gibson 2020-06-23 988 /* Request each GPIO */
f3b3ae8752adc5 Kent Gibson 2020-06-23 989 for (i = 0; i < linereq.num_lines; i++) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 990 u32 offset = linereq.offsets[i];
f3b3ae8752adc5 Kent Gibson 2020-06-23 991 struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
f3b3ae8752adc5 Kent Gibson 2020-06-23 992
f3b3ae8752adc5 Kent Gibson 2020-06-23 993 if (IS_ERR(desc)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 994 ret = PTR_ERR(desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 995 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 996 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 997
f3b3ae8752adc5 Kent Gibson 2020-06-23 998 ret = gpiod_request(desc, line->label);
f3b3ae8752adc5 Kent Gibson 2020-06-23 999 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1000 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1001
f3b3ae8752adc5 Kent Gibson 2020-06-23 1002 line->descs[i] = desc;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1003 gpioline_config_to_desc_flags(lc, &desc->flags);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1004
f3b3ae8752adc5 Kent Gibson 2020-06-23 1005 ret = gpiod_set_transitory(desc, false);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1006 if (ret < 0)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1007 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1008
f3b3ae8752adc5 Kent Gibson 2020-06-23 1009 /*
f3b3ae8752adc5 Kent Gibson 2020-06-23 1010 * Lines have to be requested explicitly for input
f3b3ae8752adc5 Kent Gibson 2020-06-23 1011 * or output, else the line will be treated "as is".
f3b3ae8752adc5 Kent Gibson 2020-06-23 1012 */
f3b3ae8752adc5 Kent Gibson 2020-06-23 1013 if (lc->flags & GPIOLINE_FLAG_V2_DIRECTION) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1014 if (lc->direction == GPIOLINE_DIRECTION_OUTPUT) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1015 int val = test_bit(i, vals);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1016
f3b3ae8752adc5 Kent Gibson 2020-06-23 1017 ret = gpiod_direction_output(desc, val);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1018 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1019 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1020 } else {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1021 ret = gpiod_direction_input(desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1022 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1023 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1024 ret = edge_detector_setup(&line->edets[i], lc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1025 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1026 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1027 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1028 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1029
f3b3ae8752adc5 Kent Gibson 2020-06-23 1030 atomic_notifier_call_chain(&desc->gdev->notifier,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1031 GPIOLINE_CHANGED_REQUESTED, desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1032
f3b3ae8752adc5 Kent Gibson 2020-06-23 1033 dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1034 offset);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1035 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1036
f3b3ae8752adc5 Kent Gibson 2020-06-23 1037 fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1038 if (fd < 0) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1039 ret = fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1040 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1041 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1042
f3b3ae8752adc5 Kent Gibson 2020-06-23 1043 file = anon_inode_getfile("gpio-line",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1044 &line_fileops,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1045 line,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1046 O_RDONLY | O_CLOEXEC);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1047 if (IS_ERR(file)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1048 ret = PTR_ERR(file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1049 goto out_put_unused_fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1050 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1051
f3b3ae8752adc5 Kent Gibson 2020-06-23 1052 linereq.fd = fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1053 if (copy_to_user(ip, &linereq, sizeof(linereq))) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1054 /*
f3b3ae8752adc5 Kent Gibson 2020-06-23 1055 * fput() will trigger the release() callback, so do not go onto
f3b3ae8752adc5 Kent Gibson 2020-06-23 1056 * the regular error cleanup path here.
f3b3ae8752adc5 Kent Gibson 2020-06-23 1057 */
f3b3ae8752adc5 Kent Gibson 2020-06-23 1058 fput(file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1059 put_unused_fd(fd);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1060 return -EFAULT;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1061 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1062
f3b3ae8752adc5 Kent Gibson 2020-06-23 1063 fd_install(fd, file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1064
f3b3ae8752adc5 Kent Gibson 2020-06-23 1065 dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1066 line->num_descs);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1067
f3b3ae8752adc5 Kent Gibson 2020-06-23 1068 return 0;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1069
f3b3ae8752adc5 Kent Gibson 2020-06-23 1070 out_put_unused_fd:
f3b3ae8752adc5 Kent Gibson 2020-06-23 1071 put_unused_fd(fd);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1072 out_free_line:
f3b3ae8752adc5 Kent Gibson 2020-06-23 1073 line_free(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1074 return ret;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1075 }
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 25304 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1
@ 2020-06-23 17:44 ` Dan Carpenter
0 siblings, 0 replies; 7+ messages in thread
From: Dan Carpenter @ 2020-06-23 17:44 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 15572 bytes --]
[ The copy_to_user() overflow code is weird. Why do we need to do a
atomic_read()? That suggests that there is a potential time of check
time of use bug where we do:
if (atomic_read(&gcdev->watch_abi_version) == 2) // <<-- time of check
event_size = sizeof(struct gpioline_info_changed_v2);
...
if (atomic_read(&gcdev->watch_abi_version) == 2) { // <<-- time of use
copy_to_user(blah, blah, event_size);
If the value for "gcdev->watch_abi_version" changes between the time
of check and the time of use then it can read beyond the end of the
buffer.
-- dan ]
Hi Kent,
Thank you for the patch! Perhaps something to improve:
url: https://github.com/0day-ci/linux/commits/Kent-Gibson/gpio-cdev-add-uAPI-V2/20200623-120634
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
config: openrisc-randconfig-m031-20200623 (attached as .config)
compiler: or1k-linux-gcc (GCC) 9.3.0
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
smatch warnings:
drivers/gpio/gpiolib-cdev.c:891 line_free() error: dereferencing freed memory 'line'
drivers/gpio/gpiolib-cdev.c:949 line_create() warn: possible memory leak of 'line'
drivers/gpio/gpiolib-cdev.c:1860 lineinfo_watch_read() error: copy_to_user() '&event_v1' too small (104 vs 168)
# https://github.com/0day-ci/linux/commit/f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
vim +/line +891 drivers/gpio/gpiolib-cdev.c
f3b3ae8752adc5 Kent Gibson 2020-06-23 877 static void line_free(struct line *line)
f3b3ae8752adc5 Kent Gibson 2020-06-23 878 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 879 int i;
f3b3ae8752adc5 Kent Gibson 2020-06-23 880
f3b3ae8752adc5 Kent Gibson 2020-06-23 881 for (i = 0; i < line->num_descs; i++) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 882 if (line->edets)
f3b3ae8752adc5 Kent Gibson 2020-06-23 883 edge_detector_stop(&line->edets[i]);
f3b3ae8752adc5 Kent Gibson 2020-06-23 884 if (line->descs[i])
f3b3ae8752adc5 Kent Gibson 2020-06-23 885 gpiod_free(line->descs[i]);
f3b3ae8752adc5 Kent Gibson 2020-06-23 886 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 887 kfifo_free(&line->events);
f3b3ae8752adc5 Kent Gibson 2020-06-23 888 kfree(line->label);
f3b3ae8752adc5 Kent Gibson 2020-06-23 889 kfree(line->edets);
f3b3ae8752adc5 Kent Gibson 2020-06-23 890 kfree(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 @891 put_device(&line->gdev->dev);
f3b3ae8752adc5 Kent Gibson 2020-06-23 892 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 893
f3b3ae8752adc5 Kent Gibson 2020-06-23 894 static int line_release(struct inode *inode, struct file *file)
f3b3ae8752adc5 Kent Gibson 2020-06-23 895 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 896 struct line *line = file->private_data;
f3b3ae8752adc5 Kent Gibson 2020-06-23 897
f3b3ae8752adc5 Kent Gibson 2020-06-23 898 line_free(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 899 return 0;
f3b3ae8752adc5 Kent Gibson 2020-06-23 900 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 901
f3b3ae8752adc5 Kent Gibson 2020-06-23 902 static const struct file_operations line_fileops = {
f3b3ae8752adc5 Kent Gibson 2020-06-23 903 .release = line_release,
f3b3ae8752adc5 Kent Gibson 2020-06-23 904 .read = line_read,
f3b3ae8752adc5 Kent Gibson 2020-06-23 905 .poll = line_poll,
f3b3ae8752adc5 Kent Gibson 2020-06-23 906 .owner = THIS_MODULE,
f3b3ae8752adc5 Kent Gibson 2020-06-23 907 .llseek = noop_llseek,
f3b3ae8752adc5 Kent Gibson 2020-06-23 908 .unlocked_ioctl = line_ioctl,
f3b3ae8752adc5 Kent Gibson 2020-06-23 909 #ifdef CONFIG_COMPAT
f3b3ae8752adc5 Kent Gibson 2020-06-23 910 .compat_ioctl = line_ioctl_compat,
f3b3ae8752adc5 Kent Gibson 2020-06-23 911 #endif
f3b3ae8752adc5 Kent Gibson 2020-06-23 912 };
f3b3ae8752adc5 Kent Gibson 2020-06-23 913
f3b3ae8752adc5 Kent Gibson 2020-06-23 914 static int line_create(struct gpio_device *gdev, void __user *ip)
f3b3ae8752adc5 Kent Gibson 2020-06-23 915 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 916 struct gpioline_request linereq;
f3b3ae8752adc5 Kent Gibson 2020-06-23 917 struct line *line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 918 struct file *file;
f3b3ae8752adc5 Kent Gibson 2020-06-23 919 int fd, i, ret, size;
f3b3ae8752adc5 Kent Gibson 2020-06-23 920 struct gpioline_config *lc;
f3b3ae8752adc5 Kent Gibson 2020-06-23 921 unsigned long *vals;
f3b3ae8752adc5 Kent Gibson 2020-06-23 922
f3b3ae8752adc5 Kent Gibson 2020-06-23 923 if (copy_from_user(&linereq, ip, sizeof(linereq)))
f3b3ae8752adc5 Kent Gibson 2020-06-23 924 return -EFAULT;
f3b3ae8752adc5 Kent Gibson 2020-06-23 925 if ((linereq.num_lines == 0) || (linereq.num_lines > GPIOLINES_MAX))
f3b3ae8752adc5 Kent Gibson 2020-06-23 926 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 927
f3b3ae8752adc5 Kent Gibson 2020-06-23 928 if (padding_not_zeroed(linereq.padding, GPIOLINE_REQUEST_PAD_SIZE))
f3b3ae8752adc5 Kent Gibson 2020-06-23 929 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 930
f3b3ae8752adc5 Kent Gibson 2020-06-23 931 lc = &linereq.config;
f3b3ae8752adc5 Kent Gibson 2020-06-23 932 ret = gpioline_config_validate(lc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 933 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 934 return ret;
f3b3ae8752adc5 Kent Gibson 2020-06-23 935
f3b3ae8752adc5 Kent Gibson 2020-06-23 936 /* event_buffer_size only valid with edge_detection */
f3b3ae8752adc5 Kent Gibson 2020-06-23 937 if ((linereq.event_buffer_size) &&
f3b3ae8752adc5 Kent Gibson 2020-06-23 938 !(linereq.config.flags & GPIOLINE_FLAG_V2_EDGE_DETECTION))
f3b3ae8752adc5 Kent Gibson 2020-06-23 939 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 940
f3b3ae8752adc5 Kent Gibson 2020-06-23 941 line = kzalloc(struct_size(line, descs, linereq.num_lines),
f3b3ae8752adc5 Kent Gibson 2020-06-23 942 GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 943 if (!line)
f3b3ae8752adc5 Kent Gibson 2020-06-23 944 return -ENOMEM;
f3b3ae8752adc5 Kent Gibson 2020-06-23 945
f3b3ae8752adc5 Kent Gibson 2020-06-23 946 line->edets = kcalloc(linereq.num_lines, sizeof(*line->edets),
f3b3ae8752adc5 Kent Gibson 2020-06-23 947 GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 948 if (!line->edets)
f3b3ae8752adc5 Kent Gibson 2020-06-23 @949 return -ENOMEM;
^^^^^^^^^^^^^^^
kfree(line) before returning.
f3b3ae8752adc5 Kent Gibson 2020-06-23 950
f3b3ae8752adc5 Kent Gibson 2020-06-23 951 for (i = 0; i < linereq.num_lines; i++)
f3b3ae8752adc5 Kent Gibson 2020-06-23 952 line->edets[i].line = line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 953
f3b3ae8752adc5 Kent Gibson 2020-06-23 954 line->gdev = gdev;
f3b3ae8752adc5 Kent Gibson 2020-06-23 955 get_device(&gdev->dev);
f3b3ae8752adc5 Kent Gibson 2020-06-23 956
f3b3ae8752adc5 Kent Gibson 2020-06-23 957 /* Make sure this is terminated */
f3b3ae8752adc5 Kent Gibson 2020-06-23 958 linereq.consumer[sizeof(linereq.consumer)-1] = '\0';
f3b3ae8752adc5 Kent Gibson 2020-06-23 959 if (strlen(linereq.consumer)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 960 line->label = kstrdup(linereq.consumer, GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 961 if (!line->label) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 962 ret = -ENOMEM;
f3b3ae8752adc5 Kent Gibson 2020-06-23 963 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 964 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 965 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 966
f3b3ae8752adc5 Kent Gibson 2020-06-23 967 mutex_init(&line->config_mutex);
f3b3ae8752adc5 Kent Gibson 2020-06-23 968 init_waitqueue_head(&line->wait);
f3b3ae8752adc5 Kent Gibson 2020-06-23 969 if (lc->edge_detection) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 970 size = linereq.event_buffer_size;
f3b3ae8752adc5 Kent Gibson 2020-06-23 971
f3b3ae8752adc5 Kent Gibson 2020-06-23 972 if (size > GPIOLINES_MAX*16)
f3b3ae8752adc5 Kent Gibson 2020-06-23 973 size = GPIOLINES_MAX*16;
f3b3ae8752adc5 Kent Gibson 2020-06-23 974 else if (size == 0)
f3b3ae8752adc5 Kent Gibson 2020-06-23 975 size = linereq.num_lines*16;
f3b3ae8752adc5 Kent Gibson 2020-06-23 976
f3b3ae8752adc5 Kent Gibson 2020-06-23 977 ret = kfifo_alloc(&line->events, size, GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 978 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 979 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 980
f3b3ae8752adc5 Kent Gibson 2020-06-23 981 line->edge_detection = lc->edge_detection;
f3b3ae8752adc5 Kent Gibson 2020-06-23 982 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 983
f3b3ae8752adc5 Kent Gibson 2020-06-23 984 atomic_set(&line->seqno, 0);
f3b3ae8752adc5 Kent Gibson 2020-06-23 985 line->num_descs = linereq.num_lines;
f3b3ae8752adc5 Kent Gibson 2020-06-23 986 vals = (unsigned long *)lc->values.bitmap;
f3b3ae8752adc5 Kent Gibson 2020-06-23 987
f3b3ae8752adc5 Kent Gibson 2020-06-23 988 /* Request each GPIO */
f3b3ae8752adc5 Kent Gibson 2020-06-23 989 for (i = 0; i < linereq.num_lines; i++) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 990 u32 offset = linereq.offsets[i];
f3b3ae8752adc5 Kent Gibson 2020-06-23 991 struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
f3b3ae8752adc5 Kent Gibson 2020-06-23 992
f3b3ae8752adc5 Kent Gibson 2020-06-23 993 if (IS_ERR(desc)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 994 ret = PTR_ERR(desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 995 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 996 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 997
f3b3ae8752adc5 Kent Gibson 2020-06-23 998 ret = gpiod_request(desc, line->label);
f3b3ae8752adc5 Kent Gibson 2020-06-23 999 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1000 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1001
f3b3ae8752adc5 Kent Gibson 2020-06-23 1002 line->descs[i] = desc;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1003 gpioline_config_to_desc_flags(lc, &desc->flags);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1004
f3b3ae8752adc5 Kent Gibson 2020-06-23 1005 ret = gpiod_set_transitory(desc, false);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1006 if (ret < 0)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1007 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1008
f3b3ae8752adc5 Kent Gibson 2020-06-23 1009 /*
f3b3ae8752adc5 Kent Gibson 2020-06-23 1010 * Lines have to be requested explicitly for input
f3b3ae8752adc5 Kent Gibson 2020-06-23 1011 * or output, else the line will be treated "as is".
f3b3ae8752adc5 Kent Gibson 2020-06-23 1012 */
f3b3ae8752adc5 Kent Gibson 2020-06-23 1013 if (lc->flags & GPIOLINE_FLAG_V2_DIRECTION) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1014 if (lc->direction == GPIOLINE_DIRECTION_OUTPUT) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1015 int val = test_bit(i, vals);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1016
f3b3ae8752adc5 Kent Gibson 2020-06-23 1017 ret = gpiod_direction_output(desc, val);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1018 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1019 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1020 } else {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1021 ret = gpiod_direction_input(desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1022 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1023 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1024 ret = edge_detector_setup(&line->edets[i], lc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1025 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1026 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1027 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1028 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1029
f3b3ae8752adc5 Kent Gibson 2020-06-23 1030 atomic_notifier_call_chain(&desc->gdev->notifier,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1031 GPIOLINE_CHANGED_REQUESTED, desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1032
f3b3ae8752adc5 Kent Gibson 2020-06-23 1033 dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1034 offset);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1035 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1036
f3b3ae8752adc5 Kent Gibson 2020-06-23 1037 fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1038 if (fd < 0) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1039 ret = fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1040 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1041 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1042
f3b3ae8752adc5 Kent Gibson 2020-06-23 1043 file = anon_inode_getfile("gpio-line",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1044 &line_fileops,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1045 line,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1046 O_RDONLY | O_CLOEXEC);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1047 if (IS_ERR(file)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1048 ret = PTR_ERR(file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1049 goto out_put_unused_fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1050 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1051
f3b3ae8752adc5 Kent Gibson 2020-06-23 1052 linereq.fd = fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1053 if (copy_to_user(ip, &linereq, sizeof(linereq))) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1054 /*
f3b3ae8752adc5 Kent Gibson 2020-06-23 1055 * fput() will trigger the release() callback, so do not go onto
f3b3ae8752adc5 Kent Gibson 2020-06-23 1056 * the regular error cleanup path here.
f3b3ae8752adc5 Kent Gibson 2020-06-23 1057 */
f3b3ae8752adc5 Kent Gibson 2020-06-23 1058 fput(file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1059 put_unused_fd(fd);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1060 return -EFAULT;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1061 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1062
f3b3ae8752adc5 Kent Gibson 2020-06-23 1063 fd_install(fd, file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1064
f3b3ae8752adc5 Kent Gibson 2020-06-23 1065 dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1066 line->num_descs);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1067
f3b3ae8752adc5 Kent Gibson 2020-06-23 1068 return 0;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1069
f3b3ae8752adc5 Kent Gibson 2020-06-23 1070 out_put_unused_fd:
f3b3ae8752adc5 Kent Gibson 2020-06-23 1071 put_unused_fd(fd);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1072 out_free_line:
f3b3ae8752adc5 Kent Gibson 2020-06-23 1073 line_free(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1074 return ret;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1075 }
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 25304 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1
@ 2020-06-23 16:56 kernel test robot
0 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2020-06-23 16:56 UTC (permalink / raw)
To: kbuild
[-- Attachment #1: Type: text/plain, Size: 15719 bytes --]
CC: kbuild-all(a)lists.01.org
In-Reply-To: <20200623040107.22270-17-warthog618@gmail.com>
References: <20200623040107.22270-17-warthog618@gmail.com>
TO: Kent Gibson <warthog618@gmail.com>
TO: linux-kernel(a)vger.kernel.org
TO: linux-gpio(a)vger.kernel.org
TO: bgolaszewski(a)baylibre.com
TO: linus.walleij(a)linaro.org
CC: Kent Gibson <warthog618@gmail.com>
Hi Kent,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on gpio/for-next]
[also build test WARNING on next-20200623]
[cannot apply to linux/master linus/master v5.8-rc2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Kent-Gibson/gpio-cdev-add-uAPI-V2/20200623-120634
base: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
:::::: branch date: 13 hours ago
:::::: commit date: 13 hours ago
config: openrisc-randconfig-m031-20200623 (attached as .config)
compiler: or1k-linux-gcc (GCC) 9.3.0
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
smatch warnings:
drivers/gpio/gpiolib-cdev.c:891 line_free() error: dereferencing freed memory 'line'
drivers/gpio/gpiolib-cdev.c:949 line_create() warn: possible memory leak of 'line'
drivers/gpio/gpiolib-cdev.c:1860 lineinfo_watch_read() error: copy_to_user() '&event_v1' too small (104 vs 168)
# https://github.com/0day-ci/linux/commit/f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout f3b3ae8752adc5ac33dcf83d49b0b02f2d7ef43b
vim +/line +891 drivers/gpio/gpiolib-cdev.c
f3b3ae8752adc5 Kent Gibson 2020-06-23 876
f3b3ae8752adc5 Kent Gibson 2020-06-23 877 static void line_free(struct line *line)
f3b3ae8752adc5 Kent Gibson 2020-06-23 878 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 879 int i;
f3b3ae8752adc5 Kent Gibson 2020-06-23 880
f3b3ae8752adc5 Kent Gibson 2020-06-23 881 for (i = 0; i < line->num_descs; i++) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 882 if (line->edets)
f3b3ae8752adc5 Kent Gibson 2020-06-23 883 edge_detector_stop(&line->edets[i]);
f3b3ae8752adc5 Kent Gibson 2020-06-23 884 if (line->descs[i])
f3b3ae8752adc5 Kent Gibson 2020-06-23 885 gpiod_free(line->descs[i]);
f3b3ae8752adc5 Kent Gibson 2020-06-23 886 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 887 kfifo_free(&line->events);
f3b3ae8752adc5 Kent Gibson 2020-06-23 888 kfree(line->label);
f3b3ae8752adc5 Kent Gibson 2020-06-23 889 kfree(line->edets);
f3b3ae8752adc5 Kent Gibson 2020-06-23 890 kfree(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 @891 put_device(&line->gdev->dev);
f3b3ae8752adc5 Kent Gibson 2020-06-23 892 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 893
f3b3ae8752adc5 Kent Gibson 2020-06-23 894 static int line_release(struct inode *inode, struct file *file)
f3b3ae8752adc5 Kent Gibson 2020-06-23 895 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 896 struct line *line = file->private_data;
f3b3ae8752adc5 Kent Gibson 2020-06-23 897
f3b3ae8752adc5 Kent Gibson 2020-06-23 898 line_free(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 899 return 0;
f3b3ae8752adc5 Kent Gibson 2020-06-23 900 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 901
f3b3ae8752adc5 Kent Gibson 2020-06-23 902 static const struct file_operations line_fileops = {
f3b3ae8752adc5 Kent Gibson 2020-06-23 903 .release = line_release,
f3b3ae8752adc5 Kent Gibson 2020-06-23 904 .read = line_read,
f3b3ae8752adc5 Kent Gibson 2020-06-23 905 .poll = line_poll,
f3b3ae8752adc5 Kent Gibson 2020-06-23 906 .owner = THIS_MODULE,
f3b3ae8752adc5 Kent Gibson 2020-06-23 907 .llseek = noop_llseek,
f3b3ae8752adc5 Kent Gibson 2020-06-23 908 .unlocked_ioctl = line_ioctl,
f3b3ae8752adc5 Kent Gibson 2020-06-23 909 #ifdef CONFIG_COMPAT
f3b3ae8752adc5 Kent Gibson 2020-06-23 910 .compat_ioctl = line_ioctl_compat,
f3b3ae8752adc5 Kent Gibson 2020-06-23 911 #endif
f3b3ae8752adc5 Kent Gibson 2020-06-23 912 };
f3b3ae8752adc5 Kent Gibson 2020-06-23 913
f3b3ae8752adc5 Kent Gibson 2020-06-23 914 static int line_create(struct gpio_device *gdev, void __user *ip)
f3b3ae8752adc5 Kent Gibson 2020-06-23 915 {
f3b3ae8752adc5 Kent Gibson 2020-06-23 916 struct gpioline_request linereq;
f3b3ae8752adc5 Kent Gibson 2020-06-23 917 struct line *line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 918 struct file *file;
f3b3ae8752adc5 Kent Gibson 2020-06-23 919 int fd, i, ret, size;
f3b3ae8752adc5 Kent Gibson 2020-06-23 920 struct gpioline_config *lc;
f3b3ae8752adc5 Kent Gibson 2020-06-23 921 unsigned long *vals;
f3b3ae8752adc5 Kent Gibson 2020-06-23 922
f3b3ae8752adc5 Kent Gibson 2020-06-23 923 if (copy_from_user(&linereq, ip, sizeof(linereq)))
f3b3ae8752adc5 Kent Gibson 2020-06-23 924 return -EFAULT;
f3b3ae8752adc5 Kent Gibson 2020-06-23 925 if ((linereq.num_lines == 0) || (linereq.num_lines > GPIOLINES_MAX))
f3b3ae8752adc5 Kent Gibson 2020-06-23 926 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 927
f3b3ae8752adc5 Kent Gibson 2020-06-23 928 if (padding_not_zeroed(linereq.padding, GPIOLINE_REQUEST_PAD_SIZE))
f3b3ae8752adc5 Kent Gibson 2020-06-23 929 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 930
f3b3ae8752adc5 Kent Gibson 2020-06-23 931 lc = &linereq.config;
f3b3ae8752adc5 Kent Gibson 2020-06-23 932 ret = gpioline_config_validate(lc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 933 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 934 return ret;
f3b3ae8752adc5 Kent Gibson 2020-06-23 935
f3b3ae8752adc5 Kent Gibson 2020-06-23 936 /* event_buffer_size only valid with edge_detection */
f3b3ae8752adc5 Kent Gibson 2020-06-23 937 if ((linereq.event_buffer_size) &&
f3b3ae8752adc5 Kent Gibson 2020-06-23 938 !(linereq.config.flags & GPIOLINE_FLAG_V2_EDGE_DETECTION))
f3b3ae8752adc5 Kent Gibson 2020-06-23 939 return -EINVAL;
f3b3ae8752adc5 Kent Gibson 2020-06-23 940
f3b3ae8752adc5 Kent Gibson 2020-06-23 941 line = kzalloc(struct_size(line, descs, linereq.num_lines),
f3b3ae8752adc5 Kent Gibson 2020-06-23 942 GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 943 if (!line)
f3b3ae8752adc5 Kent Gibson 2020-06-23 944 return -ENOMEM;
f3b3ae8752adc5 Kent Gibson 2020-06-23 945
f3b3ae8752adc5 Kent Gibson 2020-06-23 946 line->edets = kcalloc(linereq.num_lines, sizeof(*line->edets),
f3b3ae8752adc5 Kent Gibson 2020-06-23 947 GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 948 if (!line->edets)
f3b3ae8752adc5 Kent Gibson 2020-06-23 @949 return -ENOMEM;
f3b3ae8752adc5 Kent Gibson 2020-06-23 950
f3b3ae8752adc5 Kent Gibson 2020-06-23 951 for (i = 0; i < linereq.num_lines; i++)
f3b3ae8752adc5 Kent Gibson 2020-06-23 952 line->edets[i].line = line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 953
f3b3ae8752adc5 Kent Gibson 2020-06-23 954 line->gdev = gdev;
f3b3ae8752adc5 Kent Gibson 2020-06-23 955 get_device(&gdev->dev);
f3b3ae8752adc5 Kent Gibson 2020-06-23 956
f3b3ae8752adc5 Kent Gibson 2020-06-23 957 /* Make sure this is terminated */
f3b3ae8752adc5 Kent Gibson 2020-06-23 958 linereq.consumer[sizeof(linereq.consumer)-1] = '\0';
f3b3ae8752adc5 Kent Gibson 2020-06-23 959 if (strlen(linereq.consumer)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 960 line->label = kstrdup(linereq.consumer, GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 961 if (!line->label) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 962 ret = -ENOMEM;
f3b3ae8752adc5 Kent Gibson 2020-06-23 963 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 964 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 965 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 966
f3b3ae8752adc5 Kent Gibson 2020-06-23 967 mutex_init(&line->config_mutex);
f3b3ae8752adc5 Kent Gibson 2020-06-23 968 init_waitqueue_head(&line->wait);
f3b3ae8752adc5 Kent Gibson 2020-06-23 969 if (lc->edge_detection) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 970 size = linereq.event_buffer_size;
f3b3ae8752adc5 Kent Gibson 2020-06-23 971
f3b3ae8752adc5 Kent Gibson 2020-06-23 972 if (size > GPIOLINES_MAX*16)
f3b3ae8752adc5 Kent Gibson 2020-06-23 973 size = GPIOLINES_MAX*16;
f3b3ae8752adc5 Kent Gibson 2020-06-23 974 else if (size == 0)
f3b3ae8752adc5 Kent Gibson 2020-06-23 975 size = linereq.num_lines*16;
f3b3ae8752adc5 Kent Gibson 2020-06-23 976
f3b3ae8752adc5 Kent Gibson 2020-06-23 977 ret = kfifo_alloc(&line->events, size, GFP_KERNEL);
f3b3ae8752adc5 Kent Gibson 2020-06-23 978 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 979 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 980
f3b3ae8752adc5 Kent Gibson 2020-06-23 981 line->edge_detection = lc->edge_detection;
f3b3ae8752adc5 Kent Gibson 2020-06-23 982 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 983
f3b3ae8752adc5 Kent Gibson 2020-06-23 984 atomic_set(&line->seqno, 0);
f3b3ae8752adc5 Kent Gibson 2020-06-23 985 line->num_descs = linereq.num_lines;
f3b3ae8752adc5 Kent Gibson 2020-06-23 986 vals = (unsigned long *)lc->values.bitmap;
f3b3ae8752adc5 Kent Gibson 2020-06-23 987
f3b3ae8752adc5 Kent Gibson 2020-06-23 988 /* Request each GPIO */
f3b3ae8752adc5 Kent Gibson 2020-06-23 989 for (i = 0; i < linereq.num_lines; i++) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 990 u32 offset = linereq.offsets[i];
f3b3ae8752adc5 Kent Gibson 2020-06-23 991 struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
f3b3ae8752adc5 Kent Gibson 2020-06-23 992
f3b3ae8752adc5 Kent Gibson 2020-06-23 993 if (IS_ERR(desc)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 994 ret = PTR_ERR(desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 995 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 996 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 997
f3b3ae8752adc5 Kent Gibson 2020-06-23 998 ret = gpiod_request(desc, line->label);
f3b3ae8752adc5 Kent Gibson 2020-06-23 999 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1000 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1001
f3b3ae8752adc5 Kent Gibson 2020-06-23 1002 line->descs[i] = desc;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1003 gpioline_config_to_desc_flags(lc, &desc->flags);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1004
f3b3ae8752adc5 Kent Gibson 2020-06-23 1005 ret = gpiod_set_transitory(desc, false);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1006 if (ret < 0)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1007 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1008
f3b3ae8752adc5 Kent Gibson 2020-06-23 1009 /*
f3b3ae8752adc5 Kent Gibson 2020-06-23 1010 * Lines have to be requested explicitly for input
f3b3ae8752adc5 Kent Gibson 2020-06-23 1011 * or output, else the line will be treated "as is".
f3b3ae8752adc5 Kent Gibson 2020-06-23 1012 */
f3b3ae8752adc5 Kent Gibson 2020-06-23 1013 if (lc->flags & GPIOLINE_FLAG_V2_DIRECTION) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1014 if (lc->direction == GPIOLINE_DIRECTION_OUTPUT) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1015 int val = test_bit(i, vals);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1016
f3b3ae8752adc5 Kent Gibson 2020-06-23 1017 ret = gpiod_direction_output(desc, val);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1018 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1019 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1020 } else {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1021 ret = gpiod_direction_input(desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1022 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1023 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1024 ret = edge_detector_setup(&line->edets[i], lc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1025 if (ret)
f3b3ae8752adc5 Kent Gibson 2020-06-23 1026 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1027 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1028 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1029
f3b3ae8752adc5 Kent Gibson 2020-06-23 1030 atomic_notifier_call_chain(&desc->gdev->notifier,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1031 GPIOLINE_CHANGED_REQUESTED, desc);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1032
f3b3ae8752adc5 Kent Gibson 2020-06-23 1033 dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1034 offset);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1035 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1036
f3b3ae8752adc5 Kent Gibson 2020-06-23 1037 fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1038 if (fd < 0) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1039 ret = fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1040 goto out_free_line;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1041 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1042
f3b3ae8752adc5 Kent Gibson 2020-06-23 1043 file = anon_inode_getfile("gpio-line",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1044 &line_fileops,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1045 line,
f3b3ae8752adc5 Kent Gibson 2020-06-23 1046 O_RDONLY | O_CLOEXEC);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1047 if (IS_ERR(file)) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1048 ret = PTR_ERR(file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1049 goto out_put_unused_fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1050 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1051
f3b3ae8752adc5 Kent Gibson 2020-06-23 1052 linereq.fd = fd;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1053 if (copy_to_user(ip, &linereq, sizeof(linereq))) {
f3b3ae8752adc5 Kent Gibson 2020-06-23 1054 /*
f3b3ae8752adc5 Kent Gibson 2020-06-23 1055 * fput() will trigger the release() callback, so do not go onto
f3b3ae8752adc5 Kent Gibson 2020-06-23 1056 * the regular error cleanup path here.
f3b3ae8752adc5 Kent Gibson 2020-06-23 1057 */
f3b3ae8752adc5 Kent Gibson 2020-06-23 1058 fput(file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1059 put_unused_fd(fd);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1060 return -EFAULT;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1061 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1062
f3b3ae8752adc5 Kent Gibson 2020-06-23 1063 fd_install(fd, file);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1064
f3b3ae8752adc5 Kent Gibson 2020-06-23 1065 dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
f3b3ae8752adc5 Kent Gibson 2020-06-23 1066 line->num_descs);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1067
f3b3ae8752adc5 Kent Gibson 2020-06-23 1068 return 0;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1069
f3b3ae8752adc5 Kent Gibson 2020-06-23 1070 out_put_unused_fd:
f3b3ae8752adc5 Kent Gibson 2020-06-23 1071 put_unused_fd(fd);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1072 out_free_line:
f3b3ae8752adc5 Kent Gibson 2020-06-23 1073 line_free(line);
f3b3ae8752adc5 Kent Gibson 2020-06-23 1074 return ret;
f3b3ae8752adc5 Kent Gibson 2020-06-23 1075 }
f3b3ae8752adc5 Kent Gibson 2020-06-23 1076
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 25304 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1
2020-06-23 4:00 [PATCH 00/22] gpio: cdev: add uAPI V2 Kent Gibson
@ 2020-06-23 4:01 ` Kent Gibson
2020-06-23 17:44 ` Dan Carpenter
0 siblings, 1 reply; 7+ messages in thread
From: Kent Gibson @ 2020-06-23 4:01 UTC (permalink / raw)
To: linux-kernel, linux-gpio, bgolaszewski, linus.walleij; +Cc: Kent Gibson
Add implementation of the V2 uAPI up to parity with V1.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
This patch only covers the V2 functionality that is a direct analogue of
the V1. New V2 functionality is added in subsequent patches.
The core of the implementation is the struct line, which is drawn from the
existing struct linehandle_state implementation, but modified to deal with
the V2 uAPI structs.
The struct edge_detector provides the the edge detection functionality,
and is drawn from the existing lineevent_state implementation.
The two uAPI versions are mostly independent - other than where they both
provide line info changes via reads on the chip fd. As the info change
structs differ between V1 and V2, the infowatch implementation tracks which
version of the infowatch ioctl, either GPIO_GET_LINEINFO_WATCH_IOCTL or
GPIO_GET_LINEINFO_WATCH_V2_IOCTL, initiates the initial watch and returns
the corresponding info change struct to the read. The version supported
on that fd locks to that version on the first watch request, so subsequent
watches from that process must use the same uAPI version.
drivers/gpio/gpiolib-cdev.c | 934 ++++++++++++++++++++++++++++++++++--
1 file changed, 905 insertions(+), 29 deletions(-)
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index b6878fc87dfc..d4a22d78953f 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/anon_inodes.h>
+#include <linux/atomic.h>
#include <linux/bitmap.h>
+#include <linux/build_bug.h>
#include <linux/cdev.h>
#include <linux/compat.h>
#include <linux/device.h>
@@ -14,11 +16,13 @@
#include <linux/kernel.h>
#include <linux/kfifo.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/pinctrl/consumer.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/timekeeping.h>
#include <linux/uaccess.h>
+#include <linux/workqueue.h>
#include <uapi/linux/gpio.h>
#include "gpiolib.h"
@@ -34,6 +38,7 @@
* GPIO line handle management
*/
+#ifdef CONFIG_GPIO_CDEV_V1
/**
* struct linehandle_state - contains the state of a userspace handle
* @gdev: the GPIO device the handle pertains to
@@ -377,6 +382,699 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
put_device(&gdev->dev);
return ret;
}
+#endif /* CONFIG_GPIO_CDEV_V1 */
+
+/**
+ * struct edge_detector - contains the state of a line edge detector
+ * @line: the corresponding line request
+ * @irq: the interrupt triggered in response to events on this GPIO
+ * @timestamp: cache for the timestamp storing it between hardirq and IRQ
+ * thread, used to bring the timestamp close to the actual event
+ * @seqno: the seqno for the current edge event in the sequence of events
+ * for the corresponding line request. Ths is drawn from the @line.
+ * @line_seqno: the seqno for the current edge event in the sequence of
+ * events for this line.
+ */
+struct edge_detector {
+ struct line *line;
+ unsigned int irq;
+ /*
+ * timestamp and seqno are shared by edge_irq_handler and
+ * edge_irq_thread which are themselves mutually exclusive.
+ */
+ u64 timestamp;
+ u32 seqno;
+ u32 line_seqno;
+};
+
+/**
+ * struct line - contains the state of a userspace line request
+ * @gdev: the GPIO device the line request pertains to
+ * @label: consumer label used to tag descriptors
+ * @num_descs: the number of descriptors held in the descs array
+ * @edge_detection: the type of edge detection applied
+ * @wait: wait queue that handles blocking reads of events
+ * @events: KFIFO for the GPIO events
+ * @seqno: the sequence number for edge events generated on all lines in
+ * this line request. Note that this is not used when @num_descs is 1, as
+ * the line_seqno is then the same and is cheaper to calculate.
+ * @config_mutex: mutex serializing GPIOLINE_SET_CONFIG_IOCTL ioctl() calls to
+ * ensure consistency of configuration changes.
+ * @edets: an array of edge detectors, of size @num_descs
+ * @descs: the GPIO descriptors held by this line request, with @num_descs
+ * elements.
+ */
+struct line {
+ struct gpio_device *gdev;
+ const char *label;
+ u32 num_descs;
+ enum gpioline_edge edge_detection;
+ wait_queue_head_t wait;
+ DECLARE_KFIFO_PTR(events, struct gpioline_event);
+ atomic_t seqno;
+ struct mutex config_mutex; /* serializes line_set_config calls */
+ struct edge_detector *edets;
+ /* descs must be last so it can be dynamically sized */
+ struct gpio_desc *descs[];
+};
+
+static inline struct gpio_desc *edge_detector_desc(
+ const struct edge_detector *edet)
+{
+ return edet->line->descs[edet - &edet->line->edets[0]];
+}
+
+static irqreturn_t edge_irq_thread(int irq, void *p)
+{
+ struct edge_detector *edet = p;
+ struct line *line = edet->line;
+ struct gpio_desc *desc = edge_detector_desc(edet);
+ struct gpioline_event le;
+ int ret;
+
+ /* Do not leak kernel stack to userspace */
+ memset(&le, 0, sizeof(le));
+
+ /*
+ * We may be running from a nested threaded interrupt in which case
+ * we didn't get the timestamp from edge_irq_handler().
+ */
+ if (!edet->timestamp) {
+ le.timestamp = ktime_get_ns();
+ if (line->num_descs != 1)
+ edet->seqno = atomic_inc_return(&line->seqno);
+ } else {
+ le.timestamp = edet->timestamp;
+ }
+
+ edet->timestamp = 0;
+
+ if (line->edge_detection == GPIOLINE_EDGE_BOTH) {
+ int level = gpiod_get_value_cansleep(desc);
+
+ if (level)
+ /* Emit low-to-high event */
+ le.id = GPIOLINE_EVENT_RISING_EDGE;
+ else
+ /* Emit high-to-low event */
+ le.id = GPIOLINE_EVENT_FALLING_EDGE;
+ } else if (line->edge_detection == GPIOLINE_EDGE_RISING) {
+ /* Emit low-to-high event */
+ le.id = GPIOLINE_EVENT_RISING_EDGE;
+ } else if (line->edge_detection == GPIOLINE_EDGE_FALLING) {
+ /* Emit high-to-low event */
+ le.id = GPIOLINE_EVENT_FALLING_EDGE;
+ } else {
+ return IRQ_NONE;
+ }
+ edet->line_seqno++;
+ le.line_seqno = edet->line_seqno;
+ le.seqno = (line->num_descs == 1) ? le.line_seqno : edet->seqno;
+ le.offset = gpio_chip_hwgpio(desc);
+
+ ret = kfifo_in_spinlocked_noirqsave(&line->events, &le,
+ 1, &line->wait.lock);
+ if (ret)
+ wake_up_poll(&line->wait, EPOLLIN);
+ else
+ pr_debug_ratelimited("event FIFO is full - event dropped\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t edge_irq_handler(int irq, void *p)
+{
+ struct edge_detector *edet = p;
+ struct line *line = edet->line;
+
+ /*
+ * Just store the timestamp in hardirq context so we get it as
+ * close in time as possible to the actual event.
+ */
+ edet->timestamp = ktime_get_ns();
+
+ if (line->num_descs != 1)
+ edet->seqno = atomic_inc_return(&line->seqno);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int edge_detector_start(struct edge_detector *edet)
+{
+ int ret, irq, irqflags = 0;
+ struct gpio_desc *desc;
+
+ desc = edge_detector_desc(edet);
+ irq = gpiod_to_irq(desc);
+
+ if (irq <= 0)
+ return -ENODEV;
+
+ edet->seqno = 0;
+ edet->line_seqno = 0;
+
+ if (edet->line->edge_detection & GPIOLINE_EDGE_RISING)
+ irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+ IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
+ if (edet->line->edge_detection & GPIOLINE_EDGE_FALLING)
+ irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+ IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
+ irqflags |= IRQF_ONESHOT;
+
+ /* Request a thread to read the events */
+ ret = request_threaded_irq(irq,
+ edge_irq_handler,
+ edge_irq_thread,
+ irqflags,
+ edet->line->label,
+ edet);
+ if (ret)
+ return ret;
+
+ edet->irq = irq;
+ return 0;
+}
+
+static void edge_detector_stop(struct edge_detector *edet)
+{
+ if (edet->irq) {
+ free_irq(edet->irq, edet);
+ edet->irq = 0;
+ }
+}
+
+static int edge_detector_setup(struct edge_detector *edet,
+ struct gpioline_config *lc)
+{
+ if (lc->edge_detection)
+ return edge_detector_start(edet);
+ return 0;
+}
+
+static bool padding_not_zeroed(__u32 *padding, int pad_size)
+{
+ int i, sum = 0;
+
+ for (i = 0; i < pad_size; i++)
+ sum |= padding[i];
+
+ return sum;
+}
+
+#define GPIOLINE_CONFIG_VALID_FLAGS \
+ (GPIOLINE_FLAG_V2_ACTIVE_LOW | \
+ GPIOLINE_FLAG_V2_DIRECTION | \
+ GPIOLINE_FLAG_V2_DRIVE | \
+ GPIOLINE_FLAG_V2_BIAS | \
+ GPIOLINE_FLAG_V2_EDGE_DETECTION | \
+ GPIOLINE_FLAG_V2_DEBOUNCE)
+
+static int gpioline_config_validate(struct gpioline_config *config)
+{
+ u32 lflags = config->flags;
+
+ /* Return an error if an unknown flag is set */
+ if (lflags & ~GPIOLINE_CONFIG_VALID_FLAGS)
+ return -EINVAL;
+
+ /* Check ranges */
+ if (lflags & GPIOLINE_FLAG_V2_DIRECTION) {
+ if (config->direction > GPIOLINE_DIRECTION_OUTPUT)
+ return -EINVAL;
+ } else if (config->direction != 0) {
+ return -EINVAL;
+ }
+
+ if (lflags & GPIOLINE_FLAG_V2_DRIVE) {
+ if (config->drive > GPIOLINE_DRIVE_OPEN_SOURCE)
+ return -EINVAL;
+ } else if (config->drive != 0) {
+ return -EINVAL;
+ }
+
+ if (lflags & GPIOLINE_FLAG_V2_BIAS) {
+ if (config->bias > GPIOLINE_BIAS_PULL_DOWN)
+ return -EINVAL;
+ } else if (config->bias != 0) {
+ return -EINVAL;
+ }
+
+ if (lflags & GPIOLINE_FLAG_V2_EDGE_DETECTION) {
+ if (config->edge_detection > GPIOLINE_EDGE_BOTH)
+ return -EINVAL;
+ } else if (config->edge_detection != 0) {
+ return -EINVAL;
+ }
+
+ if (config->debounce_period && !(lflags & GPIOLINE_FLAG_V2_DEBOUNCE))
+ return -EINVAL;
+
+ /* Drive requires explicit output direction. */
+ if ((lflags & GPIOLINE_FLAG_V2_DRIVE) &&
+ (!(lflags & GPIOLINE_FLAG_V2_DIRECTION) ||
+ (config->direction != GPIOLINE_DIRECTION_OUTPUT)))
+ return -EINVAL;
+
+ /* Bias requires explicit direction. */
+ if ((lflags & GPIOLINE_FLAG_V2_BIAS) &&
+ !(lflags & GPIOLINE_FLAG_V2_DIRECTION))
+ return -EINVAL;
+
+ /* Edge detection requires explicit input direction. */
+ if ((lflags & GPIOLINE_FLAG_V2_EDGE_DETECTION) &&
+ (!(lflags & GPIOLINE_FLAG_V2_DIRECTION) ||
+ (config->direction != GPIOLINE_DIRECTION_INPUT)))
+ return -EINVAL;
+
+ /* Debounce requires explicit input direction. */
+ if ((lflags & GPIOLINE_FLAG_V2_DEBOUNCE) &&
+ (!(lflags & GPIOLINE_FLAG_V2_DIRECTION) ||
+ (config->direction != GPIOLINE_DIRECTION_INPUT)))
+ return -EINVAL;
+
+ if (padding_not_zeroed(config->padding, GPIOLINE_CONFIG_PAD_SIZE))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void gpioline_config_to_desc_flags(struct gpioline_config *lc,
+ unsigned long *flagsp)
+{
+ assign_bit(FLAG_ACTIVE_LOW, flagsp,
+ lc->flags & GPIOLINE_FLAG_V2_ACTIVE_LOW);
+ if (lc->flags & GPIOLINE_FLAG_V2_DRIVE) {
+ assign_bit(FLAG_OPEN_DRAIN, flagsp,
+ lc->drive == GPIOLINE_DRIVE_OPEN_DRAIN);
+ assign_bit(FLAG_OPEN_SOURCE, flagsp,
+ lc->drive == GPIOLINE_DRIVE_OPEN_SOURCE);
+ }
+ if (lc->flags & GPIOLINE_FLAG_V2_BIAS) {
+ assign_bit(FLAG_PULL_UP, flagsp,
+ lc->bias == GPIOLINE_BIAS_PULL_UP);
+ assign_bit(FLAG_PULL_DOWN, flagsp,
+ lc->bias == GPIOLINE_BIAS_PULL_DOWN);
+ assign_bit(FLAG_BIAS_DISABLE, flagsp,
+ lc->bias == GPIOLINE_BIAS_DISABLED);
+ }
+}
+
+static long line_set_config_locked(struct line *line,
+ struct gpioline_config *lc)
+{
+ struct gpio_desc *desc;
+ unsigned long *vals;
+ int i, ret;
+
+ /* disallow edge detection changes */
+ if (line->edge_detection != lc->edge_detection)
+ return -EINVAL;
+
+ desc = line->descs[0];
+
+ if (line->edge_detection != GPIOLINE_EDGE_NONE) {
+ /* disallow polarity changes */
+ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags) !=
+ ((lc->flags & GPIOLINE_FLAG_V2_ACTIVE_LOW) != 0))
+ return -EINVAL;
+ }
+
+ vals = (unsigned long *)lc->values.bitmap;
+
+ for (i = 0; i < line->num_descs; i++) {
+ desc = line->descs[i];
+ gpioline_config_to_desc_flags(lc, &desc->flags);
+ /*
+ * Lines have to be requested explicitly for input
+ * or output, else the line will be treated "as is".
+ */
+ if (lc->flags & GPIOLINE_FLAG_V2_DIRECTION) {
+ if (lc->direction == GPIOLINE_DIRECTION_OUTPUT) {
+ int val = test_bit(i, vals);
+
+ ret = gpiod_direction_output(desc, val);
+ if (ret)
+ return ret;
+ } else {
+ ret = gpiod_direction_input(desc);
+ if (ret)
+ return ret;
+ }
+ }
+
+ atomic_notifier_call_chain(&desc->gdev->notifier,
+ GPIOLINE_CHANGED_CONFIG, desc);
+ }
+ return 0;
+}
+
+static long line_set_config(struct line *line, void __user *ip)
+{
+ struct gpioline_config lc;
+ int ret;
+
+ if (copy_from_user(&lc, ip, sizeof(lc)))
+ return -EFAULT;
+
+ ret = gpioline_config_validate(&lc);
+ if (ret)
+ return ret;
+
+ mutex_lock(&line->config_mutex);
+
+ ret = line_set_config_locked(line, &lc);
+
+ mutex_unlock(&line->config_mutex);
+
+ return ret;
+}
+
+static long line_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct line *line = file->private_data;
+ void __user *ip = (void __user *)arg;
+ struct gpioline_values glv;
+ unsigned long *vals = (unsigned long *)glv.bitmap;
+ int ret;
+
+ if (cmd == GPIOLINE_GET_VALUES_IOCTL) {
+ /* NOTE: It's ok to read values of output lines. */
+ memset(&glv, 0, sizeof(glv));
+ ret = gpiod_get_array_value_complex(false,
+ true,
+ line->num_descs,
+ line->descs,
+ NULL,
+ vals);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(ip, &glv, sizeof(glv)))
+ return -EFAULT;
+
+ return 0;
+ } else if (cmd == GPIOLINE_SET_VALUES_IOCTL) {
+ /*
+ * All line descriptors were created at once with the same
+ * flags so just check if the first one is really output.
+ */
+ if (!test_bit(FLAG_IS_OUT, &line->descs[0]->flags))
+ return -EPERM;
+
+ if (copy_from_user(&glv, ip, sizeof(glv)))
+ return -EFAULT;
+
+ /* Reuse the array setting function */
+ return gpiod_set_array_value_complex(false,
+ true,
+ line->num_descs,
+ line->descs,
+ NULL,
+ vals);
+ } else if (cmd == GPIOLINE_SET_CONFIG_IOCTL) {
+ return line_set_config(line, ip);
+ }
+ return -EINVAL;
+}
+
+#ifdef CONFIG_COMPAT
+static long line_ioctl_compat(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return line_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static __poll_t line_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct line *line = file->private_data;
+ __poll_t events = 0;
+
+ poll_wait(file, &line->wait, wait);
+
+ if (!kfifo_is_empty_spinlocked_noirqsave(&line->events, &line->wait.lock))
+ events = EPOLLIN | EPOLLRDNORM;
+
+ return events;
+}
+
+static ssize_t line_read(struct file *file,
+ char __user *buf,
+ size_t count,
+ loff_t *f_ps)
+{
+ struct line *line = file->private_data;
+ struct gpioline_event le;
+ ssize_t bytes_read = 0;
+ int ret;
+
+ if (count < sizeof(le))
+ return -EINVAL;
+
+ do {
+ spin_lock(&line->wait.lock);
+ if (kfifo_is_empty(&line->events)) {
+ if (bytes_read) {
+ spin_unlock(&line->wait.lock);
+ return bytes_read;
+ }
+
+ if (file->f_flags & O_NONBLOCK) {
+ spin_unlock(&line->wait.lock);
+ return -EAGAIN;
+ }
+
+ ret = wait_event_interruptible_locked(line->wait,
+ !kfifo_is_empty(&line->events));
+ if (ret) {
+ spin_unlock(&line->wait.lock);
+ return ret;
+ }
+ }
+
+ ret = kfifo_out(&line->events, &le, 1);
+ spin_unlock(&line->wait.lock);
+ if (ret != 1) {
+ /*
+ * This should never happen - we were holding the lock
+ * from the moment we learned the fifo is no longer
+ * empty until now.
+ */
+ ret = -EIO;
+ break;
+ }
+
+ if (copy_to_user(buf + bytes_read, &le, sizeof(le)))
+ return -EFAULT;
+ bytes_read += sizeof(le);
+ } while (count >= bytes_read + sizeof(le));
+
+ return bytes_read;
+}
+
+static void line_free(struct line *line)
+{
+ int i;
+
+ for (i = 0; i < line->num_descs; i++) {
+ if (line->edets)
+ edge_detector_stop(&line->edets[i]);
+ if (line->descs[i])
+ gpiod_free(line->descs[i]);
+ }
+ kfifo_free(&line->events);
+ kfree(line->label);
+ kfree(line->edets);
+ kfree(line);
+ put_device(&line->gdev->dev);
+}
+
+static int line_release(struct inode *inode, struct file *file)
+{
+ struct line *line = file->private_data;
+
+ line_free(line);
+ return 0;
+}
+
+static const struct file_operations line_fileops = {
+ .release = line_release,
+ .read = line_read,
+ .poll = line_poll,
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+ .unlocked_ioctl = line_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = line_ioctl_compat,
+#endif
+};
+
+static int line_create(struct gpio_device *gdev, void __user *ip)
+{
+ struct gpioline_request linereq;
+ struct line *line;
+ struct file *file;
+ int fd, i, ret, size;
+ struct gpioline_config *lc;
+ unsigned long *vals;
+
+ if (copy_from_user(&linereq, ip, sizeof(linereq)))
+ return -EFAULT;
+ if ((linereq.num_lines == 0) || (linereq.num_lines > GPIOLINES_MAX))
+ return -EINVAL;
+
+ if (padding_not_zeroed(linereq.padding, GPIOLINE_REQUEST_PAD_SIZE))
+ return -EINVAL;
+
+ lc = &linereq.config;
+ ret = gpioline_config_validate(lc);
+ if (ret)
+ return ret;
+
+ /* event_buffer_size only valid with edge_detection */
+ if ((linereq.event_buffer_size) &&
+ !(linereq.config.flags & GPIOLINE_FLAG_V2_EDGE_DETECTION))
+ return -EINVAL;
+
+ line = kzalloc(struct_size(line, descs, linereq.num_lines),
+ GFP_KERNEL);
+ if (!line)
+ return -ENOMEM;
+
+ line->edets = kcalloc(linereq.num_lines, sizeof(*line->edets),
+ GFP_KERNEL);
+ if (!line->edets)
+ return -ENOMEM;
+
+ for (i = 0; i < linereq.num_lines; i++)
+ line->edets[i].line = line;
+
+ line->gdev = gdev;
+ get_device(&gdev->dev);
+
+ /* Make sure this is terminated */
+ linereq.consumer[sizeof(linereq.consumer)-1] = '\0';
+ if (strlen(linereq.consumer)) {
+ line->label = kstrdup(linereq.consumer, GFP_KERNEL);
+ if (!line->label) {
+ ret = -ENOMEM;
+ goto out_free_line;
+ }
+ }
+
+ mutex_init(&line->config_mutex);
+ init_waitqueue_head(&line->wait);
+ if (lc->edge_detection) {
+ size = linereq.event_buffer_size;
+
+ if (size > GPIOLINES_MAX*16)
+ size = GPIOLINES_MAX*16;
+ else if (size == 0)
+ size = linereq.num_lines*16;
+
+ ret = kfifo_alloc(&line->events, size, GFP_KERNEL);
+ if (ret)
+ goto out_free_line;
+
+ line->edge_detection = lc->edge_detection;
+ }
+
+ atomic_set(&line->seqno, 0);
+ line->num_descs = linereq.num_lines;
+ vals = (unsigned long *)lc->values.bitmap;
+
+ /* Request each GPIO */
+ for (i = 0; i < linereq.num_lines; i++) {
+ u32 offset = linereq.offsets[i];
+ struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset);
+
+ if (IS_ERR(desc)) {
+ ret = PTR_ERR(desc);
+ goto out_free_line;
+ }
+
+ ret = gpiod_request(desc, line->label);
+ if (ret)
+ goto out_free_line;
+
+ line->descs[i] = desc;
+ gpioline_config_to_desc_flags(lc, &desc->flags);
+
+ ret = gpiod_set_transitory(desc, false);
+ if (ret < 0)
+ goto out_free_line;
+
+ /*
+ * Lines have to be requested explicitly for input
+ * or output, else the line will be treated "as is".
+ */
+ if (lc->flags & GPIOLINE_FLAG_V2_DIRECTION) {
+ if (lc->direction == GPIOLINE_DIRECTION_OUTPUT) {
+ int val = test_bit(i, vals);
+
+ ret = gpiod_direction_output(desc, val);
+ if (ret)
+ goto out_free_line;
+ } else {
+ ret = gpiod_direction_input(desc);
+ if (ret)
+ goto out_free_line;
+ ret = edge_detector_setup(&line->edets[i], lc);
+ if (ret)
+ goto out_free_line;
+ }
+ }
+
+ atomic_notifier_call_chain(&desc->gdev->notifier,
+ GPIOLINE_CHANGED_REQUESTED, desc);
+
+ dev_dbg(&gdev->dev, "registered chardev handle for line %d\n",
+ offset);
+ }
+
+ fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ ret = fd;
+ goto out_free_line;
+ }
+
+ file = anon_inode_getfile("gpio-line",
+ &line_fileops,
+ line,
+ O_RDONLY | O_CLOEXEC);
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(file);
+ goto out_put_unused_fd;
+ }
+
+ linereq.fd = fd;
+ if (copy_to_user(ip, &linereq, sizeof(linereq))) {
+ /*
+ * fput() will trigger the release() callback, so do not go onto
+ * the regular error cleanup path here.
+ */
+ fput(file);
+ put_unused_fd(fd);
+ return -EFAULT;
+ }
+
+ fd_install(fd, file);
+
+ dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
+ line->num_descs);
+
+ return 0;
+
+out_put_unused_fd:
+ put_unused_fd(fd);
+out_free_line:
+ line_free(line);
+ return ret;
+}
+
+#ifdef CONFIG_GPIO_CDEV_V1
/*
* GPIO line event management
@@ -750,10 +1448,63 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
return ret;
}
+static void gpioline_info_v2_to_v1(struct gpioline_info_v2 *info_v2,
+ struct gpioline_info *info_v1)
+{
+ int flagsv2 = info_v2->config.flags;
+
+ strncpy(info_v1->name, info_v2->name, sizeof(info_v1->name));
+ strncpy(info_v1->consumer, info_v2->consumer,
+ sizeof(info_v1->consumer));
+ info_v1->line_offset = info_v2->offset;
+ info_v1->flags = 0;
+
+ if (flagsv2 & GPIOLINE_FLAG_V2_USED)
+ info_v1->flags |= GPIOLINE_FLAG_KERNEL;
+
+ if (info_v2->config.direction == GPIOLINE_DIRECTION_OUTPUT)
+ info_v1->flags |= GPIOLINE_FLAG_IS_OUT;
+
+ if (flagsv2 & GPIOLINE_FLAG_V2_ACTIVE_LOW)
+ info_v1->flags |= GPIOLINE_FLAG_ACTIVE_LOW;
+
+ if (flagsv2 & GPIOLINE_FLAG_V2_DRIVE) {
+ enum gpioline_drive drive = info_v2->config.drive;
+
+ if (drive == GPIOLINE_DRIVE_OPEN_DRAIN)
+ info_v1->flags |= GPIOLINE_FLAG_OPEN_DRAIN;
+ else if (drive == GPIOLINE_DRIVE_OPEN_SOURCE)
+ info_v1->flags |= GPIOLINE_FLAG_OPEN_SOURCE;
+ }
+
+ if (flagsv2 & GPIOLINE_FLAG_V2_BIAS) {
+ enum gpioline_bias bias = info_v2->config.bias;
+
+ if (bias == GPIOLINE_BIAS_PULL_UP)
+ info_v1->flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
+ else if (bias == GPIOLINE_BIAS_PULL_DOWN)
+ info_v1->flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
+ else if (bias == GPIOLINE_BIAS_DISABLED)
+ info_v1->flags |= GPIOLINE_FLAG_BIAS_DISABLE;
+ }
+}
+
+static void gpioline_info_changed_v2_to_v1(
+ struct gpioline_info_changed_v2 *lic_v2,
+ struct gpioline_info_changed *lic_v1)
+{
+ gpioline_info_v2_to_v1(&lic_v2->info, &lic_v1->info);
+ lic_v1->timestamp = lic_v2->timestamp;
+ lic_v1->event_type = lic_v2->event_type;
+}
+
+#endif /* CONFIG_GPIO_CDEV_V1 */
+
static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
- struct gpioline_info *info)
+ struct gpioline_info_v2 *info)
{
struct gpio_chip *gc = desc->gdev->chip;
+ struct gpioline_config *lc = &info->config;
bool ok_for_pinctrl;
unsigned long flags;
@@ -765,7 +1516,7 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
* lock common to both frameworks?
*/
ok_for_pinctrl =
- pinctrl_gpio_can_use_line(gc->base + info->line_offset);
+ pinctrl_gpio_can_use_line(gc->base + info->offset);
spin_lock_irqsave(&gpio_lock, flags);
@@ -783,34 +1534,46 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
info->consumer[0] = '\0';
}
+ lc->flags = GPIOLINE_FLAG_V2_DIRECTION;
/*
* Userspace only need to know that the kernel is using this GPIO so
* it can't use it.
*/
- info->flags = 0;
if (test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_IS_HOGGED, &desc->flags) ||
test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags) ||
test_bit(FLAG_SYSFS, &desc->flags) ||
!ok_for_pinctrl)
- info->flags |= GPIOLINE_FLAG_KERNEL;
- if (test_bit(FLAG_IS_OUT, &desc->flags))
- info->flags |= GPIOLINE_FLAG_IS_OUT;
+ lc->flags |= GPIOLINE_FLAG_V2_USED;
+ if (test_bit(FLAG_IS_OUT, &desc->flags)) {
+ lc->direction = GPIOLINE_DIRECTION_OUTPUT;
+ lc->flags |= GPIOLINE_FLAG_V2_DRIVE;
+ if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
+ lc->drive = GPIOLINE_DRIVE_OPEN_DRAIN;
+ else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
+ lc->drive = GPIOLINE_DRIVE_OPEN_SOURCE;
+ else
+ lc->drive = GPIOLINE_DRIVE_PUSH_PULL;
+ } else {
+ lc->direction = GPIOLINE_DIRECTION_INPUT;
+ }
+
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
- info->flags |= GPIOLINE_FLAG_ACTIVE_LOW;
- if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
- info->flags |= (GPIOLINE_FLAG_OPEN_DRAIN |
- GPIOLINE_FLAG_IS_OUT);
- if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
- info->flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
- GPIOLINE_FLAG_IS_OUT);
- if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
- info->flags |= GPIOLINE_FLAG_BIAS_DISABLE;
- if (test_bit(FLAG_PULL_DOWN, &desc->flags))
- info->flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
- if (test_bit(FLAG_PULL_UP, &desc->flags))
- info->flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
+ lc->flags |= GPIOLINE_FLAG_V2_ACTIVE_LOW;
+
+ if (test_bit(FLAG_BIAS_DISABLE, &desc->flags)) {
+ lc->flags |= GPIOLINE_FLAG_V2_BIAS;
+ lc->bias = GPIOLINE_BIAS_DISABLED;
+ } else if (test_bit(FLAG_PULL_DOWN, &desc->flags)) {
+ lc->flags |= GPIOLINE_FLAG_V2_BIAS;
+ lc->bias = GPIOLINE_BIAS_PULL_DOWN;
+ } else if (test_bit(FLAG_PULL_UP, &desc->flags)) {
+ lc->flags |= GPIOLINE_FLAG_V2_BIAS;
+ lc->bias = GPIOLINE_BIAS_PULL_UP;
+ }
+
+ lc->edge_detection = 0;
spin_unlock_irqrestore(&gpio_lock, flags);
}
@@ -818,11 +1581,62 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
struct gpio_chardev_data {
struct gpio_device *gdev;
wait_queue_head_t wait;
- DECLARE_KFIFO(events, struct gpioline_info_changed, 32);
+ DECLARE_KFIFO(events, struct gpioline_info_changed_v2, 32);
struct notifier_block lineinfo_changed_nb;
unsigned long *watched_lines;
+#ifdef CONFIG_GPIO_CDEV_V1
+ atomic_t watch_abi_version;
+#endif
};
+#ifdef CONFIG_GPIO_CDEV_V1
+static int lineinfo_ensure_abi_version(struct gpio_chardev_data *cdata,
+ unsigned int version)
+{
+ int abiv = atomic_read(&cdata->watch_abi_version);
+
+ if (abiv == 0) {
+ atomic_cmpxchg(&cdata->watch_abi_version, 0, version);
+ abiv = atomic_read(&cdata->watch_abi_version);
+ }
+ if (abiv != version)
+ return -EPERM;
+ return 0;
+}
+#endif
+
+static int lineinfo_get(struct gpio_chardev_data *gcdev, void __user *ip,
+ unsigned int cmd)
+{
+ struct gpio_desc *desc;
+ struct gpioline_info_v2 lineinfo;
+
+ if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
+ return -EFAULT;
+
+ if (padding_not_zeroed(lineinfo.padding, GPIOLINE_INFO_V2_PAD_SIZE))
+ return -EINVAL;
+
+ desc = gpiochip_get_desc(gcdev->gdev->chip, lineinfo.offset);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ if (cmd == GPIO_GET_LINEINFO_WATCH_V2_IOCTL) {
+#ifdef CONFIG_GPIO_CDEV_V1
+ if (lineinfo_ensure_abi_version(gcdev, 2))
+ return -EPERM;
+#endif
+ if (test_and_set_bit(lineinfo.offset, gcdev->watched_lines))
+ return -EBUSY;
+ }
+ gpio_desc_to_lineinfo(desc, &lineinfo);
+
+ if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
/*
* gpio_ioctl() - ioctl handler for the GPIO chardev
*/
@@ -855,8 +1669,10 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
return -EFAULT;
return 0;
+#ifdef CONFIG_GPIO_CDEV_V1
} else if (cmd == GPIO_GET_LINEINFO_IOCTL) {
struct gpioline_info lineinfo;
+ struct gpioline_info_v2 lineinfo_v2;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
@@ -866,7 +1682,9 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (IS_ERR(desc))
return PTR_ERR(desc);
- gpio_desc_to_lineinfo(desc, &lineinfo);
+ lineinfo_v2.offset = lineinfo.line_offset;
+ gpio_desc_to_lineinfo(desc, &lineinfo_v2);
+ gpioline_info_v2_to_v1(&lineinfo_v2, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
@@ -877,6 +1695,7 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return lineevent_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
struct gpioline_info lineinfo;
+ struct gpioline_info_v2 lineinfo_v2;
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT;
@@ -886,15 +1705,26 @@ static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (IS_ERR(desc))
return PTR_ERR(desc);
+ if (lineinfo_ensure_abi_version(gcdev, 1))
+ return -EPERM;
+
if (test_and_set_bit(lineinfo.line_offset, gcdev->watched_lines))
return -EBUSY;
- gpio_desc_to_lineinfo(desc, &lineinfo);
+ lineinfo_v2.offset = lineinfo.line_offset;
+ gpio_desc_to_lineinfo(desc, &lineinfo_v2);
+ gpioline_info_v2_to_v1(&lineinfo_v2, &lineinfo);
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
return 0;
+#endif /* CONFIG_GPIO_CDEV_V1 */
+ } else if (cmd == GPIO_GET_LINEINFO_V2_IOCTL ||
+ cmd == GPIO_GET_LINEINFO_WATCH_V2_IOCTL) {
+ return lineinfo_get(gcdev, ip, cmd);
+ } else if (cmd == GPIO_GET_LINE_IOCTL) {
+ return line_create(gdev, ip);
} else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) {
if (copy_from_user(&offset, ip, sizeof(offset)))
return -EFAULT;
@@ -928,7 +1758,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct gpio_chardev_data *gcdev = to_gpio_chardev_data(nb);
- struct gpioline_info_changed chg;
+ struct gpioline_info_changed_v2 chg;
struct gpio_desc *desc = data;
int ret;
@@ -936,7 +1766,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
return NOTIFY_DONE;
memset(&chg, 0, sizeof(chg));
- chg.info.line_offset = gpio_chip_hwgpio(desc);
+ chg.info.offset = gpio_chip_hwgpio(desc);
chg.event_type = action;
chg.timestamp = ktime_get_ns();
gpio_desc_to_lineinfo(desc, &chg.info);
@@ -969,12 +1799,16 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
size_t count, loff_t *off)
{
struct gpio_chardev_data *gcdev = file->private_data;
- struct gpioline_info_changed event;
+ struct gpioline_info_changed_v2 event;
ssize_t bytes_read = 0;
int ret;
+ size_t event_size;
- if (count < sizeof(event))
+#ifndef CONFIG_GPIO_CDEV_V1
+ event_size = sizeof(struct gpioline_info_changed_v2);
+ if (count < event_size)
return -EINVAL;
+#endif
do {
spin_lock(&gcdev->wait.lock);
@@ -996,7 +1830,17 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
return ret;
}
}
-
+#ifdef CONFIG_GPIO_CDEV_V1
+ /* must be after kfifo check so watch_abi_version is set */
+ if (atomic_read(&gcdev->watch_abi_version) == 2)
+ event_size = sizeof(struct gpioline_info_changed_v2);
+ else
+ event_size = sizeof(struct gpioline_info_changed);
+ if (count < event_size) {
+ spin_unlock(&gcdev->wait.lock);
+ return -EINVAL;
+ }
+#endif
ret = kfifo_out(&gcdev->events, &event, 1);
spin_unlock(&gcdev->wait.lock);
if (ret != 1) {
@@ -1005,9 +1849,23 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
/* We should never get here. See lineevent_read(). */
}
- if (copy_to_user(buf + bytes_read, &event, sizeof(event)))
+#ifdef CONFIG_GPIO_CDEV_V1
+ if (atomic_read(&gcdev->watch_abi_version) == 2) {
+ if (copy_to_user(buf + bytes_read, &event, event_size))
+ return -EFAULT;
+ } else {
+ struct gpioline_info_changed event_v1;
+
+ gpioline_info_changed_v2_to_v1(&event, &event_v1);
+ if (copy_to_user(buf + bytes_read, &event_v1,
+ event_size))
+ return -EFAULT;
+ }
+#else
+ if (copy_to_user(buf + bytes_read, &event, event_size))
return -EFAULT;
- bytes_read += sizeof(event);
+#endif
+ bytes_read += event_size;
} while (count >= bytes_read + sizeof(event));
return bytes_read;
@@ -1121,4 +1979,22 @@ int gpiolib_cdev_register(struct gpio_device *gdev, dev_t devt)
void gpiolib_cdev_unregister(struct gpio_device *gdev)
{
cdev_device_del(&gdev->chrdev, &gdev->dev);
+
+ /*
+ * array sizes must be a multiple of 8 to ensure 64bit alignment and
+ * to not create holes in the struct packing.
+ */
+ BUILD_BUG_ON(GPIOLINES_MAX % 8);
+ BUILD_BUG_ON(GPIO_MAX_NAME_SIZE % 8);
+
+ /*
+ * check that uAPI structs are 64bit aligned for 32/64bit
+ * compatibility
+ */
+ BUILD_BUG_ON(sizeof(struct gpioline_config) % 8);
+ BUILD_BUG_ON(sizeof(struct gpioline_request) % 8);
+ BUILD_BUG_ON(sizeof(struct gpioline_info_v2) % 8);
+ BUILD_BUG_ON(sizeof(struct gpioline_info_changed_v2) % 8);
+ BUILD_BUG_ON(sizeof(struct gpioline_event) % 8);
+ BUILD_BUG_ON(sizeof(struct gpioline_values) % 8);
}
--
2.27.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2020-06-23 23:23 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-23 7:26 [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1 kernel test robot
-- strict thread matches above, loose matches on Subject: below --
2020-06-23 16:56 kernel test robot
2020-06-23 4:00 [PATCH 00/22] gpio: cdev: add uAPI V2 Kent Gibson
2020-06-23 4:01 ` [PATCH 16/22] gpiolib: cdev: add V2 uAPI implementation to parity with V1 Kent Gibson
2020-06-23 17:44 ` Dan Carpenter
2020-06-23 17:44 ` Dan Carpenter
2020-06-23 17:44 ` Dan Carpenter
2020-06-23 23:23 ` Kent Gibson
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.