[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1428569224-23820-109-git-send-email-lizf@kernel.org>
Date: Thu, 9 Apr 2015 16:45:57 +0800
From: lizf@...nel.org
To: stable@...r.kernel.org
Cc: linux-kernel@...r.kernel.org, Johan Hovold <johan@...nel.org>,
Linus Walleij <linus.walleij@...aro.org>,
Zefan Li <lizefan@...wei.com>
Subject: [PATCH 3.4 109/176] gpio: sysfs: fix gpio attribute-creation race
From: Johan Hovold <johan@...nel.org>
3.4.107-rc1 review patch. If anyone has any objections, please let me know.
------------------
commit ebbeba120ab2ec6ac5f3afc1425ec6ff0b77ad6f upstream.
Fix attribute-creation race with userspace by using the default group
to create also the contingent gpio device attributes.
Fixes: d8f388d8dc8d ("gpio: sysfs interface")
Signed-off-by: Johan Hovold <johan@...nel.org>
Signed-off-by: Linus Walleij <linus.walleij@...aro.org>
[lizf:
- adjust filename
- call gpio_to_irq() instead of gpiod_to_irq]
Signed-off-by: Zefan Li <lizefan@...wei.com>
---
drivers/gpio/gpiolib.c | 63 ++++++++++++++++++++++++++++++++------------------
1 file changed, 41 insertions(+), 22 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4db6c55..6c4443b 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -60,6 +60,7 @@ struct gpio_desc {
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
+#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */
#define ID_SHIFT 16 /* add new flags before this one */
@@ -545,12 +546,45 @@ static ssize_t gpio_active_low_store(struct device *dev,
static DEVICE_ATTR(active_low, 0644,
gpio_active_low_show, gpio_active_low_store);
+static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
+ int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct gpio_desc *desc = dev_get_drvdata(dev);
+ unsigned gpio = desc - gpio_desc;
+ umode_t mode = attr->mode;
+ bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags);
+
+ if (attr == &dev_attr_direction.attr) {
+ if (!show_direction)
+ mode = 0;
+ } else if (attr == &dev_attr_edge.attr) {
+ if (gpio_to_irq(gpio) < 0)
+ mode = 0;
+ if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags))
+ mode = 0;
+ }
+
+ return mode;
+}
+
static struct attribute *gpio_attrs[] = {
+ &dev_attr_direction.attr,
+ &dev_attr_edge.attr,
&dev_attr_value.attr,
&dev_attr_active_low.attr,
NULL,
};
-ATTRIBUTE_GROUPS(gpio);
+
+static const struct attribute_group gpio_group = {
+ .attrs = gpio_attrs,
+ .is_visible = gpio_is_visible,
+};
+
+static const struct attribute_group *gpio_groups[] = {
+ &gpio_group,
+ NULL
+};
/*
* /sys/class/gpio/gpiochipN/
@@ -727,8 +761,11 @@ int gpio_export(unsigned gpio, bool direction_may_change)
return -EPERM;
}
- if (!desc->chip->direction_input || !desc->chip->direction_output)
- direction_may_change = false;
+ if (desc->chip->direction_input && desc->chip->direction_output &&
+ direction_may_change) {
+ set_bit(FLAG_SYSFS_DIR, &desc->flags);
+ }
+
spin_unlock_irqrestore(&gpio_lock, flags);
if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
@@ -742,27 +779,10 @@ int gpio_export(unsigned gpio, bool direction_may_change)
goto fail_unlock;
}
- if (direction_may_change) {
- status = device_create_file(dev, &dev_attr_direction);
- if (status)
- goto fail_unregister_device;
- }
-
- if (gpio_to_irq(gpio) >= 0 && (direction_may_change ||
- !test_bit(FLAG_IS_OUT, &desc->flags))) {
- status = device_create_file(dev, &dev_attr_edge);
- if (status)
- 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:
mutex_unlock(&sysfs_lock);
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
@@ -893,6 +913,7 @@ void gpio_unexport(unsigned gpio)
dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (dev) {
gpio_setup_irq(desc, dev, 0);
+ clear_bit(FLAG_SYSFS_DIR, &desc->flags);
clear_bit(FLAG_EXPORT, &desc->flags);
} else
status = -ENODEV;
@@ -900,8 +921,6 @@ void gpio_unexport(unsigned gpio)
mutex_unlock(&sysfs_lock);
if (dev) {
- device_remove_file(dev, &dev_attr_edge);
- device_remove_file(dev, &dev_attr_direction);
device_unregister(dev);
put_device(dev);
}
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists