--- /dev/null
+From 483d821108791092798f5d230686868112927044 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan@kernel.org>
+Date: Tue, 21 Apr 2015 17:42:09 +0200
+Subject: gpio: sysfs: fix memory leaks and device hotplug
+
+From: Johan Hovold <johan@kernel.org>
+
+commit 483d821108791092798f5d230686868112927044 upstream.
+
+Unregister GPIOs requested through sysfs at chip remove to avoid leaking
+the associated memory and sysfs entries.
+
+The stale sysfs entries prevented the gpio numbers from being exported
+when the gpio range was later reused (e.g. at device reconnect).
+
+This also fixes the related module-reference leak.
+
+Note that kernfs makes sure that any on-going sysfs operations finish
+before the class devices are unregistered and that further accesses
+fail.
+
+The chip exported flag is used to prevent gpiod exports during removal.
+This also makes it harder to trigger, but does not fix, the related race
+between gpiochip_remove and export_store, which is really a race with
+gpiod_request that needs to be addressed separately.
+
+Also note that this would prevent the crashes (e.g. NULL-dereferences)
+at reconnect that affects pre-3.18 kernels, as well as use-after-free on
+operations on open attribute files on pre-3.14 kernels (prior to
+kernfs).
+
+Fixes: d8f388d8dc8d ("gpio: sysfs interface")
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpio/gpiolib.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -752,6 +752,7 @@ static struct class gpio_class = {
+ */
+ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+ {
++ struct gpio_chip *chip;
+ unsigned long flags;
+ int status;
+ const char *ioname = NULL;
+@@ -769,8 +770,16 @@ static int gpiod_export(struct gpio_desc
+ return -EINVAL;
+ }
+
++ chip = desc->chip;
++
+ mutex_lock(&sysfs_lock);
+
++ /* check if chip is being removed */
++ if (!chip || !chip->exported) {
++ status = -ENODEV;
++ goto fail_unlock;
++ }
++
+ spin_lock_irqsave(&gpio_lock, flags);
+ if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
+ test_bit(FLAG_EXPORT, &desc->flags)) {
+@@ -1040,6 +1049,8 @@ static void gpiochip_unexport(struct gpi
+ {
+ int status;
+ struct device *dev;
++ struct gpio_desc *desc;
++ unsigned int i;
+
+ mutex_lock(&sysfs_lock);
+ dev = class_find_device(&gpio_class, NULL, chip, match_export);
+@@ -1047,6 +1058,7 @@ static void gpiochip_unexport(struct gpi
+ sysfs_remove_group(&dev->kobj, &gpiochip_attr_group);
+ put_device(dev);
+ device_unregister(dev);
++ /* prevent further gpiod exports */
+ chip->exported = 0;
+ status = 0;
+ } else
+@@ -1056,6 +1068,13 @@ static void gpiochip_unexport(struct gpi
+ if (status)
+ pr_debug("%s: chip %s status %d\n", __func__,
+ chip->label, status);
++
++ /* unregister gpiod class devices owned by sysfs */
++ for (i = 0; i < chip->ngpio; i++) {
++ desc = &chip->desc[i];
++ if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
++ gpiod_free(desc);
++ }
+ }
+
+ static int __init gpiolib_sysfs_init(void)
--- /dev/null
+From 01cca93a9491ed95992523ff7e79dd9bfcdea8e0 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan@kernel.org>
+Date: Mon, 12 Jan 2015 17:12:29 +0100
+Subject: gpio: unregister gpiochip device before removing it
+
+From: Johan Hovold <johan@kernel.org>
+
+commit 01cca93a9491ed95992523ff7e79dd9bfcdea8e0 upstream.
+
+Unregister gpiochip device (used to export information through sysfs)
+before removing it internally. This way removal will reverse addition.
+
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ drivers/gpio/gpiolib.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -1265,6 +1265,8 @@ int gpiochip_remove(struct gpio_chip *ch
+ int status = 0;
+ unsigned id;
+
++ gpiochip_unexport(chip);
++
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ gpiochip_remove_pin_ranges(chip);
+@@ -1285,9 +1287,6 @@ int gpiochip_remove(struct gpio_chip *ch
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+- if (status == 0)
+- gpiochip_unexport(chip);
+-
+ return status;
+ }
+ EXPORT_SYMBOL_GPL(gpiochip_remove);