Skip to contentSkip to conversation

gpio: sysfs: backports of memleak fixes to 3.12

PATCH Superseded Johan Hovold 2 participants 7 messages Jan 26, 2015 – Jan 27, 2015

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover gpio: sysfs: backports of memleak fixes to 3.12

Hi Greg,

Here are backports of two fixes for memory leaks in the gpio sysfs interface that are needed in the stable trees.

Tested on 3.12, but will not compile on 3.10 or earlier which lacks device_create_with_groups. I'll send a second version for these kernels.

Johan

Johan Hovold (2):
gpio: sysfs: fix gpio-chip device-attribute leak
gpio: sysfs: fix gpio device-attribute leak

 drivers/gpio/gpiolib.c | 46 +++++++++++++++++++++-------------------------
 1 file changed, 21 insertions(+), 25 deletions(-)
Signature · 1 line
2.0.5
#1 lore raw

PATCH 1/2 gpio: sysfs: fix gpio-chip device-attribute leak

Commit 121b6a79955a3a3fd7bbb9b8cb88d5b9dad6283d upstream.

The gpio-chip device attributes were never destroyed when the device was removed.

Fix by using device_create_with_groups() to create the device attributes of the chip class device.

Note that this also fixes the attribute-creation race with userspace.

Fixes d8f388d8dc8d ("gpio: sysfs interface")
Cc stable <[email protected]> # v2.6.27+
---
 drivers/gpio/gpiolib.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)
drivers/gpio/gpiolib.c +8 -11
index 0dee0e0c247a..dd4d6ffacc30 100644
@@ -627,16 +627,13 @@ static ssize_t chip_ngpio_show(struct device *dev,
 }
 static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
 
-static const struct attribute *gpiochip_attrs[] = {
+static struct attribute *gpiochip_attrs[] = {
 	&dev_attr_base.attr,
 	&dev_attr_label.attr,
 	&dev_attr_ngpio.attr,
 	NULL,
 };
-
-static const struct attribute_group gpiochip_attr_group = {
-	.attrs = (struct attribute **) gpiochip_attrs,
-};
+ATTRIBUTE_GROUPS(gpiochip);
 
 /*
  * /sys/class/gpio/export ... write-only
@@ -1001,13 +998,13 @@ static int gpiochip_export(struct gpio_chip *chip)
 
 	/* use chip->base for the ID; it's already known to be unique */
 	mutex_lock(&sysfs_lock);
-	dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,
-				"gpiochip%d", chip->base);
-	if (!IS_ERR(dev)) {
-		status = sysfs_create_group(&dev->kobj,
-				&gpiochip_attr_group);
-	} else
+	dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
+					chip, gpiochip_groups,
+					"gpiochip%d", chip->base);
+	if (IS_ERR(dev))
 		status = PTR_ERR(dev);
+	else
+		status = 0;
 	chip->exported = (status == 0);
 	mutex_unlock(&sysfs_lock);
 
Signature · 1 line
2.0.5
#2 lore raw

PATCH 2/2 gpio: sysfs: fix gpio device-attribute leak

In reply to Johan Hovold

Commit 0915e6feb38de8d3601819992a5bd050201a56fa upstream.

The gpio device attributes were never destroyed when the gpio was unexported (or on export failures).

Use device_create_with_groups() to create the default device attributes of the gpio class device. Note that this also fixes the attribute-creation race with userspace for these attributes.

Remove contingent attributes in export error path and on unexport.

Fixes d8f388d8dc8d ("gpio: sysfs interface")
Cc stable <[email protected]> # v2.6.27+
---
 drivers/gpio/gpiolib.c | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)
drivers/gpio/gpiolib.c +13 -14
index dd4d6ffacc30..8380709b66d2 100644
@@ -362,7 +362,7 @@ static ssize_t gpio_value_store(struct device *dev,
 	return status;
 }
 
-static const DEVICE_ATTR(value, 0644,
+static DEVICE_ATTR(value, 0644,
 		gpio_value_show, gpio_value_store);
 
 static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
@@ -580,18 +580,16 @@ static ssize_t gpio_active_low_store(struct device *dev,
 	return status ? : size;
 }
 
-static const DEVICE_ATTR(active_low, 0644,
+static DEVICE_ATTR(active_low, 0644,
 		gpio_active_low_show, gpio_active_low_store);
 
-static const struct attribute *gpio_attrs[] = {
+static struct attribute *gpio_attrs[] = {
 	&dev_attr_value.attr,
 	&dev_attr_active_low.attr,
 	NULL,
 };
 
-static const struct attribute_group gpio_attr_group = {
-	.attrs = (struct attribute **) gpio_attrs,
-};
+ATTRIBUTE_GROUPS(gpio);
 
 /*
  * /sys/class/gpio/gpiochipN/
@@ -788,18 +786,15 @@ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 	if (desc->chip->names && desc->chip->names[offset])
 		ioname = desc->chip->names[offset];
 
-	dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-			    desc, ioname ? ioname : "gpio%u",
-			    desc_to_gpio(desc));
+	dev = device_create_with_groups(&gpio_class, desc->chip->dev,
+					MKDEV(0, 0), desc, gpio_groups,
+					ioname ? ioname : "gpio%u",
+					desc_to_gpio(desc));
 	if (IS_ERR(dev)) {
 		status = PTR_ERR(dev);
 		goto fail_unlock;
 	}
 
-	status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
-	if (status)
-		goto fail_unregister_device;
-
 	if (direction_may_change) {
 		status = device_create_file(dev, &dev_attr_direction);
 		if (status)
@@ -810,13 +805,15 @@ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 				       !test_bit(FLAG_IS_OUT, &desc->flags))) {
 		status = device_create_file(dev, &dev_attr_edge);
 		if (status)
-			goto fail_unregister_device;
+			goto fail_remove_attr_direction;
 	}
 
 	set_bit(FLAG_EXPORT, &desc->flags);
 	mutex_unlock(&sysfs_lock);
 	return 0;
 
+fail_remove_attr_direction:
+	device_remove_file(dev, &dev_attr_direction);
 fail_unregister_device:
 	device_unregister(dev);
 fail_unlock:
@@ -959,6 +956,8 @@ static void gpiod_unexport(struct gpio_desc *desc)
 
 		dev = class_find_device(&gpio_class, NULL, desc, match_export);
 		if (dev) {
+			device_remove_file(dev, &dev_attr_edge);
+			device_remove_file(dev, &dev_attr_direction);
 			gpio_setup_irq(desc, dev, 0);
 			clear_bit(FLAG_EXPORT, &desc->flags);
 		} else
Signature · 1 line
2.0.5
#3 lore raw

cover gpio: sysfs: backports of memleak fixes to 3.10

In reply to Johan Hovold

And here are the backports of the two fixes for memory leaks in the gpio sysfs interface for 3.10 and earlier.

Tested on 3.12 and compile-tested on 3.10.

Johan

Johan Hovold (2):
gpio: sysfs: fix gpio-chip device-attribute leak
gpio: sysfs: fix gpio device-attribute leak

 drivers/gpio/gpiolib.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)
Signature · 1 line
2.0.5
#4 lore raw

PATCH 1/2 gpio: sysfs: fix gpio-chip device-attribute leak

Commit 121b6a79955a3a3fd7bbb9b8cb88d5b9dad6283d upstream.

The gpio-chip device attributes were never destroyed when the device was removed.

Fix by using device_create_with_groups() to create the device attributes of the chip class device.

Note that this also fixes the attribute-creation race with userspace.

Fixes d8f388d8dc8d ("gpio: sysfs interface")
Cc stable <[email protected]> # v2.6.27+

[johan: fix leak without device_create_with_groups, which wasn't introduced until 3.11 ]

---
 drivers/gpio/gpiolib.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/gpio/gpiolib.c +3 -2
index 0dee0e0c247a..bc3d59efe80b 100644
@@ -627,7 +627,7 @@ static ssize_t chip_ngpio_show(struct device *dev,
 }
 static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
 
-static const struct attribute *gpiochip_attrs[] = {
+static struct attribute *gpiochip_attrs[] = {
 	&dev_attr_base.attr,
 	&dev_attr_label.attr,
 	&dev_attr_ngpio.attr,
@@ -635,7 +635,7 @@ static const struct attribute *gpiochip_attrs[] = {
 };
 
 static const struct attribute_group gpiochip_attr_group = {
-	.attrs = (struct attribute **) gpiochip_attrs,
+	.attrs = gpiochip_attrs,
 };
 
 /*
@@ -1036,6 +1036,7 @@ static void gpiochip_unexport(struct gpio_chip *chip)
 	mutex_lock(&sysfs_lock);
 	dev = class_find_device(&gpio_class, NULL, chip, match_export);
 	if (dev) {
+		sysfs_remove_group(&dev->kobj, &gpiochip_attr_group);
 		put_device(dev);
 		device_unregister(dev);
 		chip->exported = 0;
Signature · 1 line
2.0.5
#5 lore raw

PATCH 2/2 gpio: sysfs: fix gpio device-attribute leak

In reply to Johan Hovold

Commit 0915e6feb38de8d3601819992a5bd050201a56fa upstream.

The gpio device attributes were never destroyed when the gpio was unexported (or on export failures).

Use device_create_with_groups() to create the default device attributes of the gpio class device. Note that this also fixes the attribute-creation race with userspace for these attributes.

Remove contingent attributes in export error path and on unexport.

Fixes d8f388d8dc8d ("gpio: sysfs interface")
Cc stable <[email protected]> # v2.6.27+

[johan: fix leaks without device_create_with_groups, which wasn't introduced until 3.11 ]

---
 drivers/gpio/gpiolib.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)
drivers/gpio/gpiolib.c +13 -6
index bc3d59efe80b..4b2a26b62025 100644
@@ -362,7 +362,7 @@ static ssize_t gpio_value_store(struct device *dev,
 	return status;
 }
 
-static const DEVICE_ATTR(value, 0644,
+static DEVICE_ATTR(value, 0644,
 		gpio_value_show, gpio_value_store);
 
 static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
@@ -580,17 +580,17 @@ static ssize_t gpio_active_low_store(struct device *dev,
 	return status ? : size;
 }
 
-static const DEVICE_ATTR(active_low, 0644,
+static DEVICE_ATTR(active_low, 0644,
 		gpio_active_low_show, gpio_active_low_store);
 
-static const struct attribute *gpio_attrs[] = {
+static struct attribute *gpio_attrs[] = {
 	&dev_attr_value.attr,
 	&dev_attr_active_low.attr,
 	NULL,
 };
 
 static const struct attribute_group gpio_attr_group = {
-	.attrs = (struct attribute **) gpio_attrs,
+       .attrs = gpio_attrs,
 };
 
 /*
@@ -806,20 +806,24 @@ static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 	if (direction_may_change) {
 		status = device_create_file(dev, &dev_attr_direction);
 		if (status)
-			goto fail_unregister_device;
+			goto fail_remove_attr_group;
 	}
 
 	if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
 				       !test_bit(FLAG_IS_OUT, &desc->flags))) {
 		status = device_create_file(dev, &dev_attr_edge);
 		if (status)
-			goto fail_unregister_device;
+			goto fail_remove_attr_direction;
 	}
 
 	set_bit(FLAG_EXPORT, &desc->flags);
 	mutex_unlock(&sysfs_lock);
 	return 0;
 
+fail_remove_attr_direction:
+	device_remove_file(dev, &dev_attr_direction);
+fail_remove_attr_group:
+	sysfs_remove_group(&dev->kobj, &gpio_attr_group);
 fail_unregister_device:
 	device_unregister(dev);
 fail_unlock:
@@ -962,6 +966,9 @@ static void gpiod_unexport(struct gpio_desc *desc)
 
 		dev = class_find_device(&gpio_class, NULL, desc, match_export);
 		if (dev) {
+			device_remove_file(dev, &dev_attr_edge);
+			device_remove_file(dev, &dev_attr_direction);
+			sysfs_remove_group(&dev->kobj, &gpio_attr_group);
 			gpio_setup_irq(desc, dev, 0);
 			clear_bit(FLAG_EXPORT, &desc->flags);
 		} else
Signature · 1 line
2.0.5
#6 lore raw
In reply to Johan Hovold
Quoted 7 lines · Johan Hovold

Hi Greg,

Here are backports of two fixes for memory leaks in the gpio sysfs interface that are needed in the stable trees.

Tested on 3.12, but will not compile on 3.10 or earlier which lacks device_create_with_groups. I'll send a second version for these kernels.

Thanks for all of these, now applied.

greg k-h