lkml.org 
[lkml]   [2015]   [Feb]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.2 117/152] gpio: sysfs: fix gpio attribute-creation race
    3.2.67-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Johan Hovold <johan@kernel.org>

    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@kernel.org>
    Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
    [bwh: Backported to 3.2:
    - Adjust filenames, context
    - Use gpio_to_desc(), not gpiod_to_desc(), in gpio_is_visible()
    - gpio_is_visible() must return mode_t]
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    --- a/drivers/gpio/gpiolib.c
    +++ b/drivers/gpio/gpiolib.c
    @@ -58,6 +58,7 @@ struct gpio_desc {
    #define FLAG_TRIG_FALL 5 /* trigger on falling edge */
    #define FLAG_TRIG_RISE 6 /* trigger on rising edge */
    #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
    +#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */

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

    @@ -543,12 +544,45 @@ static ssize_t gpio_active_low_store(str
    static DEVICE_ATTR(active_low, 0644,
    gpio_active_low_show, gpio_active_low_store);

    +static mode_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;
    + mode_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/
    @@ -723,8 +757,11 @@ int gpio_export(unsigned gpio, bool dire
    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])
    @@ -738,27 +775,10 @@ int gpio_export(unsigned gpio, bool dire
    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);
    @@ -889,6 +909,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;
    @@ -896,8 +917,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);
    }


    \
     
     \ /
      Last update: 2015-02-17 04:01    [W:4.507 / U:0.048 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site