aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpiolib-sysfs.c
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2015-01-13 07:00:06 -0500
committerLinus Walleij <linus.walleij@linaro.org>2015-01-15 11:20:56 -0500
commitebbeba120ab2ec6ac5f3afc1425ec6ff0b77ad6f (patch)
tree34ced1282b4b34b9ee79e9e0549dbca3ade7aab6 /drivers/gpio/gpiolib-sysfs.c
parent0915e6feb38de8d3601819992a5bd050201a56fa (diff)
gpio: sysfs: fix gpio attribute-creation race
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@kernel.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib-sysfs.c')
-rw-r--r--drivers/gpio/gpiolib-sysfs.c61
1 files changed, 39 insertions, 22 deletions
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index fd4d9423f6e6..f62aa115d79a 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -356,12 +356,44 @@ static ssize_t gpio_active_low_store(struct device *dev,
356static DEVICE_ATTR(active_low, 0644, 356static DEVICE_ATTR(active_low, 0644,
357 gpio_active_low_show, gpio_active_low_store); 357 gpio_active_low_show, gpio_active_low_store);
358 358
359static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
360 int n)
361{
362 struct device *dev = container_of(kobj, struct device, kobj);
363 struct gpio_desc *desc = dev_get_drvdata(dev);
364 umode_t mode = attr->mode;
365 bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags);
366
367 if (attr == &dev_attr_direction.attr) {
368 if (!show_direction)
369 mode = 0;
370 } else if (attr == &dev_attr_edge.attr) {
371 if (gpiod_to_irq(desc) < 0)
372 mode = 0;
373 if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags))
374 mode = 0;
375 }
376
377 return mode;
378}
379
359static struct attribute *gpio_attrs[] = { 380static struct attribute *gpio_attrs[] = {
381 &dev_attr_direction.attr,
382 &dev_attr_edge.attr,
360 &dev_attr_value.attr, 383 &dev_attr_value.attr,
361 &dev_attr_active_low.attr, 384 &dev_attr_active_low.attr,
362 NULL, 385 NULL,
363}; 386};
364ATTRIBUTE_GROUPS(gpio); 387
388static const struct attribute_group gpio_group = {
389 .attrs = gpio_attrs,
390 .is_visible = gpio_is_visible,
391};
392
393static const struct attribute_group *gpio_groups[] = {
394 &gpio_group,
395 NULL
396};
365 397
366/* 398/*
367 * /sys/class/gpio/gpiochipN/ 399 * /sys/class/gpio/gpiochipN/
@@ -550,8 +582,11 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
550 goto fail_unlock; 582 goto fail_unlock;
551 } 583 }
552 584
553 if (!desc->chip->direction_input || !desc->chip->direction_output) 585 if (desc->chip->direction_input && desc->chip->direction_output &&
554 direction_may_change = false; 586 direction_may_change) {
587 set_bit(FLAG_SYSFS_DIR, &desc->flags);
588 }
589
555 spin_unlock_irqrestore(&gpio_lock, flags); 590 spin_unlock_irqrestore(&gpio_lock, flags);
556 591
557 offset = gpio_chip_hwgpio(desc); 592 offset = gpio_chip_hwgpio(desc);
@@ -567,27 +602,10 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
567 goto fail_unlock; 602 goto fail_unlock;
568 } 603 }
569 604
570 if (direction_may_change) {
571 status = device_create_file(dev, &dev_attr_direction);
572 if (status)
573 goto fail_unregister_device;
574 }
575
576 if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
577 !test_bit(FLAG_IS_OUT, &desc->flags))) {
578 status = device_create_file(dev, &dev_attr_edge);
579 if (status)
580 goto fail_remove_attr_direction;
581 }
582
583 set_bit(FLAG_EXPORT, &desc->flags); 605 set_bit(FLAG_EXPORT, &desc->flags);
584 mutex_unlock(&sysfs_lock); 606 mutex_unlock(&sysfs_lock);
585 return 0; 607 return 0;
586 608
587fail_remove_attr_direction:
588 device_remove_file(dev, &dev_attr_direction);
589fail_unregister_device:
590 device_unregister(dev);
591fail_unlock: 609fail_unlock:
592 mutex_unlock(&sysfs_lock); 610 mutex_unlock(&sysfs_lock);
593 gpiod_dbg(desc, "%s: status %d\n", __func__, status); 611 gpiod_dbg(desc, "%s: status %d\n", __func__, status);
@@ -711,6 +729,7 @@ void gpiod_unexport(struct gpio_desc *desc)
711 dev = class_find_device(&gpio_class, NULL, desc, match_export); 729 dev = class_find_device(&gpio_class, NULL, desc, match_export);
712 if (dev) { 730 if (dev) {
713 gpio_setup_irq(desc, dev, 0); 731 gpio_setup_irq(desc, dev, 0);
732 clear_bit(FLAG_SYSFS_DIR, &desc->flags);
714 clear_bit(FLAG_EXPORT, &desc->flags); 733 clear_bit(FLAG_EXPORT, &desc->flags);
715 } else 734 } else
716 status = -ENODEV; 735 status = -ENODEV;
@@ -719,8 +738,6 @@ void gpiod_unexport(struct gpio_desc *desc)
719 mutex_unlock(&sysfs_lock); 738 mutex_unlock(&sysfs_lock);
720 739
721 if (dev) { 740 if (dev) {
722 device_remove_file(dev, &dev_attr_edge);
723 device_remove_file(dev, &dev_attr_direction);
724 device_unregister(dev); 741 device_unregister(dev);
725 put_device(dev); 742 put_device(dev);
726 } 743 }