Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpiolib: cdev: fix frame size warning in gpio_ioctl()

The kernel test robot reports the following warning in [1]:

drivers/gpio/gpiolib-cdev.c: In function 'gpio_ioctl':
>>drivers/gpio/gpiolib-cdev.c:1437:1: warning: the frame size of 1040 bytes is larger than 1024 bytes [-Wframe-larger-than=]

Refactor gpio_ioctl() to handle each ioctl in its own helper function
and so reduce the variables stored on the stack to those explicitly
required to service the ioctl at hand.

The lineinfo_get_v1() helper handles both the GPIO_GET_LINEINFO_IOCTL
and GPIO_GET_LINEINFO_WATCH_IOCTL, as per the corresponding v2
implementation - lineinfo_get().

[1] https://lore.kernel.org/lkml/202012270910.VW3qc1ER-lkp@intel.com/

Fixes: aad955842d1c ("gpiolib: cdev: support GPIO_V2_GET_LINEINFO_IOCTL and GPIO_V2_GET_LINEINFO_WATCH_IOCTL")
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Kent Gibson <warthog618@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

authored by

Kent Gibson and committed by
Bartosz Golaszewski
2e202ad8 5c8fe583

+73 -72
+73 -72
drivers/gpio/gpiolib-cdev.c
··· 1979 1979 #endif 1980 1980 }; 1981 1981 1982 + static int chipinfo_get(struct gpio_chardev_data *cdev, void __user *ip) 1983 + { 1984 + struct gpio_device *gdev = cdev->gdev; 1985 + struct gpiochip_info chipinfo; 1986 + 1987 + memset(&chipinfo, 0, sizeof(chipinfo)); 1988 + 1989 + strscpy(chipinfo.name, dev_name(&gdev->dev), sizeof(chipinfo.name)); 1990 + strscpy(chipinfo.label, gdev->label, sizeof(chipinfo.label)); 1991 + chipinfo.lines = gdev->ngpio; 1992 + if (copy_to_user(ip, &chipinfo, sizeof(chipinfo))) 1993 + return -EFAULT; 1994 + return 0; 1995 + } 1996 + 1982 1997 #ifdef CONFIG_GPIO_CDEV_V1 1983 1998 /* 1984 1999 * returns 0 if the versions match, else the previously selected ABI version ··· 2007 1992 return 0; 2008 1993 2009 1994 return abiv; 1995 + } 1996 + 1997 + static int lineinfo_get_v1(struct gpio_chardev_data *cdev, void __user *ip, 1998 + bool watch) 1999 + { 2000 + struct gpio_desc *desc; 2001 + struct gpioline_info lineinfo; 2002 + struct gpio_v2_line_info lineinfo_v2; 2003 + 2004 + if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) 2005 + return -EFAULT; 2006 + 2007 + /* this doubles as a range check on line_offset */ 2008 + desc = gpiochip_get_desc(cdev->gdev->chip, lineinfo.line_offset); 2009 + if (IS_ERR(desc)) 2010 + return PTR_ERR(desc); 2011 + 2012 + if (watch) { 2013 + if (lineinfo_ensure_abi_version(cdev, 1)) 2014 + return -EPERM; 2015 + 2016 + if (test_and_set_bit(lineinfo.line_offset, cdev->watched_lines)) 2017 + return -EBUSY; 2018 + } 2019 + 2020 + gpio_desc_to_lineinfo(desc, &lineinfo_v2); 2021 + gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo); 2022 + 2023 + if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { 2024 + if (watch) 2025 + clear_bit(lineinfo.line_offset, cdev->watched_lines); 2026 + return -EFAULT; 2027 + } 2028 + 2029 + return 0; 2010 2030 } 2011 2031 #endif 2012 2032 ··· 2080 2030 return 0; 2081 2031 } 2082 2032 2033 + static int lineinfo_unwatch(struct gpio_chardev_data *cdev, void __user *ip) 2034 + { 2035 + __u32 offset; 2036 + 2037 + if (copy_from_user(&offset, ip, sizeof(offset))) 2038 + return -EFAULT; 2039 + 2040 + if (offset >= cdev->gdev->ngpio) 2041 + return -EINVAL; 2042 + 2043 + if (!test_and_clear_bit(offset, cdev->watched_lines)) 2044 + return -EBUSY; 2045 + 2046 + return 0; 2047 + } 2048 + 2083 2049 /* 2084 2050 * gpio_ioctl() - ioctl handler for the GPIO chardev 2085 2051 */ ··· 2103 2037 { 2104 2038 struct gpio_chardev_data *cdev = file->private_data; 2105 2039 struct gpio_device *gdev = cdev->gdev; 2106 - struct gpio_chip *gc = gdev->chip; 2107 2040 void __user *ip = (void __user *)arg; 2108 - __u32 offset; 2109 2041 2110 2042 /* We fail any subsequent ioctl():s when the chip is gone */ 2111 - if (!gc) 2043 + if (!gdev->chip) 2112 2044 return -ENODEV; 2113 2045 2114 2046 /* Fill in the struct and pass to userspace */ 2115 2047 if (cmd == GPIO_GET_CHIPINFO_IOCTL) { 2116 - struct gpiochip_info chipinfo; 2117 - 2118 - memset(&chipinfo, 0, sizeof(chipinfo)); 2119 - 2120 - strscpy(chipinfo.name, dev_name(&gdev->dev), 2121 - sizeof(chipinfo.name)); 2122 - strscpy(chipinfo.label, gdev->label, 2123 - sizeof(chipinfo.label)); 2124 - chipinfo.lines = gdev->ngpio; 2125 - if (copy_to_user(ip, &chipinfo, sizeof(chipinfo))) 2126 - return -EFAULT; 2127 - return 0; 2048 + return chipinfo_get(cdev, ip); 2128 2049 #ifdef CONFIG_GPIO_CDEV_V1 2129 - } else if (cmd == GPIO_GET_LINEINFO_IOCTL) { 2130 - struct gpio_desc *desc; 2131 - struct gpioline_info lineinfo; 2132 - struct gpio_v2_line_info lineinfo_v2; 2133 - 2134 - if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) 2135 - return -EFAULT; 2136 - 2137 - /* this doubles as a range check on line_offset */ 2138 - desc = gpiochip_get_desc(gc, lineinfo.line_offset); 2139 - if (IS_ERR(desc)) 2140 - return PTR_ERR(desc); 2141 - 2142 - gpio_desc_to_lineinfo(desc, &lineinfo_v2); 2143 - gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo); 2144 - 2145 - if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) 2146 - return -EFAULT; 2147 - return 0; 2148 2050 } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { 2149 2051 return linehandle_create(gdev, ip); 2150 2052 } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) { 2151 2053 return lineevent_create(gdev, ip); 2152 - } else if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) { 2153 - struct gpio_desc *desc; 2154 - struct gpioline_info lineinfo; 2155 - struct gpio_v2_line_info lineinfo_v2; 2156 - 2157 - if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) 2158 - return -EFAULT; 2159 - 2160 - /* this doubles as a range check on line_offset */ 2161 - desc = gpiochip_get_desc(gc, lineinfo.line_offset); 2162 - if (IS_ERR(desc)) 2163 - return PTR_ERR(desc); 2164 - 2165 - if (lineinfo_ensure_abi_version(cdev, 1)) 2166 - return -EPERM; 2167 - 2168 - if (test_and_set_bit(lineinfo.line_offset, cdev->watched_lines)) 2169 - return -EBUSY; 2170 - 2171 - gpio_desc_to_lineinfo(desc, &lineinfo_v2); 2172 - gpio_v2_line_info_to_v1(&lineinfo_v2, &lineinfo); 2173 - 2174 - if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { 2175 - clear_bit(lineinfo.line_offset, cdev->watched_lines); 2176 - return -EFAULT; 2177 - } 2178 - 2179 - return 0; 2054 + } else if (cmd == GPIO_GET_LINEINFO_IOCTL || 2055 + cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) { 2056 + return lineinfo_get_v1(cdev, ip, 2057 + cmd == GPIO_GET_LINEINFO_WATCH_IOCTL); 2180 2058 #endif /* CONFIG_GPIO_CDEV_V1 */ 2181 2059 } else if (cmd == GPIO_V2_GET_LINEINFO_IOCTL || 2182 2060 cmd == GPIO_V2_GET_LINEINFO_WATCH_IOCTL) { ··· 2129 2119 } else if (cmd == GPIO_V2_GET_LINE_IOCTL) { 2130 2120 return linereq_create(gdev, ip); 2131 2121 } else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) { 2132 - if (copy_from_user(&offset, ip, sizeof(offset))) 2133 - return -EFAULT; 2134 - 2135 - if (offset >= cdev->gdev->ngpio) 2136 - return -EINVAL; 2137 - 2138 - if (!test_and_clear_bit(offset, cdev->watched_lines)) 2139 - return -EBUSY; 2140 - 2141 - return 0; 2122 + return lineinfo_unwatch(cdev, ip); 2142 2123 } 2143 2124 return -EINVAL; 2144 2125 }