Skip to content

Commit ebbeba1

Browse files
jhovoldlinusw
authored andcommitted
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: d8f388d ("gpio: sysfs interface") Signed-off-by: Johan Hovold <johan@kernel.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent 0915e6f commit ebbeba1

File tree

2 files changed

+40
-22
lines changed

2 files changed

+40
-22
lines changed

drivers/gpio/gpiolib-sysfs.c

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -356,12 +356,44 @@ static ssize_t gpio_active_low_store(struct device *dev,
356356
static DEVICE_ATTR(active_low, 0644,
357357
gpio_active_low_show, gpio_active_low_store);
358358

359+
static 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+
359380
static struct attribute *gpio_attrs[] = {
381+
&dev_attr_direction.attr,
382+
&dev_attr_edge.attr,
360383
&dev_attr_value.attr,
361384
&dev_attr_active_low.attr,
362385
NULL,
363386
};
364-
ATTRIBUTE_GROUPS(gpio);
387+
388+
static const struct attribute_group gpio_group = {
389+
.attrs = gpio_attrs,
390+
.is_visible = gpio_is_visible,
391+
};
392+
393+
static const struct attribute_group *gpio_groups[] = {
394+
&gpio_group,
395+
NULL
396+
};
365397

366398
/*
367399
* /sys/class/gpio/gpiochipN/
@@ -550,8 +582,11 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
550582
goto fail_unlock;
551583
}
552584

553-
if (!desc->chip->direction_input || !desc->chip->direction_output)
554-
direction_may_change = false;
585+
if (desc->chip->direction_input && desc->chip->direction_output &&
586+
direction_may_change) {
587+
set_bit(FLAG_SYSFS_DIR, &desc->flags);
588+
}
589+
555590
spin_unlock_irqrestore(&gpio_lock, flags);
556591

557592
offset = gpio_chip_hwgpio(desc);
@@ -567,27 +602,10 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
567602
goto fail_unlock;
568603
}
569604

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-
583605
set_bit(FLAG_EXPORT, &desc->flags);
584606
mutex_unlock(&sysfs_lock);
585607
return 0;
586608

587-
fail_remove_attr_direction:
588-
device_remove_file(dev, &dev_attr_direction);
589-
fail_unregister_device:
590-
device_unregister(dev);
591609
fail_unlock:
592610
mutex_unlock(&sysfs_lock);
593611
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
@@ -711,6 +729,7 @@ void gpiod_unexport(struct gpio_desc *desc)
711729
dev = class_find_device(&gpio_class, NULL, desc, match_export);
712730
if (dev) {
713731
gpio_setup_irq(desc, dev, 0);
732+
clear_bit(FLAG_SYSFS_DIR, &desc->flags);
714733
clear_bit(FLAG_EXPORT, &desc->flags);
715734
} else
716735
status = -ENODEV;
@@ -719,8 +738,6 @@ void gpiod_unexport(struct gpio_desc *desc)
719738
mutex_unlock(&sysfs_lock);
720739

721740
if (dev) {
722-
device_remove_file(dev, &dev_attr_edge);
723-
device_remove_file(dev, &dev_attr_direction);
724741
device_unregister(dev);
725742
put_device(dev);
726743
}

drivers/gpio/gpiolib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ struct gpio_desc {
7777
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
7878
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
7979
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
80+
#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */
8081

8182
#define ID_SHIFT 16 /* add new flags before this one */
8283

0 commit comments

Comments
 (0)