diff options
author | Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> | 2016-06-03 19:10:02 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-06-24 10:22:02 -0700 |
commit | 55d32af72aba4e0310fc38a39ef38b2ac73163a5 (patch) | |
tree | 59e179cae66e29b02686356744c7f6d10304ef79 /drivers | |
parent | d917611dc7234bc15662b07cde0ad4d5438277ce (diff) | |
download | lwn-55d32af72aba4e0310fc38a39ef38b2ac73163a5.tar.gz lwn-55d32af72aba4e0310fc38a39ef38b2ac73163a5.zip |
gpiolib: Fix unaligned used of reference counters
commit f4833b8cc7edab57d3f3033e549111a546c2e02b upstream.
gpiolib relies on the reference counters to clean up the gpio_device
structure.
Although the number of get/put is properly aligned on gpiolib.c
itself, it does not take into consideration how the referece counters
are affected by other external functions such as cdev_add and device_add.
Because of this, after the last call to put_device, the reference counter
has a value of +3, therefore never calling gpiodevice_release.
Due to the fact that some of the device has already been cleaned on
gpiochip_remove, the library will end up OOPsing the kernel (e.g. a call
to of_gpiochip_find_and_xlate).
Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/gpiolib.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c3ee98e996d8..719d1114f8eb 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -438,7 +438,6 @@ static void gpiodevice_release(struct device *dev) { struct gpio_device *gdev = dev_get_drvdata(dev); - cdev_del(&gdev->chrdev); list_del(&gdev->list); ida_simple_remove(&gpio_ida, gdev->id); kfree(gdev->label); @@ -471,7 +470,6 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) /* From this point, the .release() function cleans up gpio_device */ gdev->dev.release = gpiodevice_release; - get_device(&gdev->dev); pr_debug("%s: registered GPIOs %d to %d on device: %s (%s)\n", __func__, gdev->base, gdev->base + gdev->ngpio - 1, dev_name(&gdev->dev), gdev->chip->label ? : "generic"); @@ -742,6 +740,8 @@ void gpiochip_remove(struct gpio_chip *chip) * be removed, else it will be dangling until the last user is * gone. */ + cdev_del(&gdev->chrdev); + device_del(&gdev->dev); put_device(&gdev->dev); } EXPORT_SYMBOL_GPL(gpiochip_remove); |