Commit 14b5d6dd40b3091cb5f566568baa4a74dc619286

Authored by Florian Fainelli
Committed by Richard Purdie
1 parent 0493a4ff10

leds: Fix race between LED device uevent and actual attributes creation

If we were to dynamically register/unregister leds and have udev or other
daemons handle the leds class uevents, we would be notified of the adding of a
new LED and if the daemon immediately tries to open one of the attributes of
the led device, it would fail with a "no such file or directory" error since
this the attributes are not yet created. Fix this by switching attributes to be
class-wide, such that the driver core will register these attributes with
device_add_attrs and then emit the kobject_uevent ADD signal.

Signed-off-by:  Fainelli <ffainelli@freebox.fr>
Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>

Showing 1 changed file with 8 additions and 32 deletions Side-by-side Diff

drivers/leds/led-class.c
... ... @@ -72,11 +72,14 @@
72 72 return sprintf(buf, "%u\n", led_cdev->max_brightness);
73 73 }
74 74  
75   -static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
76   -static DEVICE_ATTR(max_brightness, 0444, led_max_brightness_show, NULL);
  75 +static struct device_attribute led_class_attrs[] = {
  76 + __ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
  77 + __ATTR(max_brightness, 0644, led_max_brightness_show, NULL),
77 78 #ifdef CONFIG_LEDS_TRIGGERS
78   -static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
  79 + __ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
79 80 #endif
  81 + __ATTR_NULL,
  82 +};
80 83  
81 84 /**
82 85 * led_classdev_suspend - suspend an led_classdev.
83 86  
... ... @@ -127,18 +130,11 @@
127 130 */
128 131 int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
129 132 {
130   - int rc;
131   -
132 133 led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,
133 134 "%s", led_cdev->name);
134 135 if (IS_ERR(led_cdev->dev))
135 136 return PTR_ERR(led_cdev->dev);
136 137  
137   - /* register the attributes */
138   - rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
139   - if (rc)
140   - goto err_out;
141   -
142 138 #ifdef CONFIG_LEDS_TRIGGERS
143 139 init_rwsem(&led_cdev->trigger_lock);
144 140 #endif
145 141  
... ... @@ -150,17 +146,9 @@
150 146 if (!led_cdev->max_brightness)
151 147 led_cdev->max_brightness = LED_FULL;
152 148  
153   - rc = device_create_file(led_cdev->dev, &dev_attr_max_brightness);
154   - if (rc)
155   - goto err_out_attr_max;
156   -
157 149 led_update_brightness(led_cdev);
158 150  
159 151 #ifdef CONFIG_LEDS_TRIGGERS
160   - rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
161   - if (rc)
162   - goto err_out_led_list;
163   -
164 152 led_trigger_set_default(led_cdev);
165 153 #endif
166 154  
167 155  
... ... @@ -168,18 +156,8 @@
168 156 led_cdev->name);
169 157  
170 158 return 0;
171   -
172   -#ifdef CONFIG_LEDS_TRIGGERS
173   -err_out_led_list:
174   - device_remove_file(led_cdev->dev, &dev_attr_max_brightness);
175   -#endif
176   -err_out_attr_max:
177   - device_remove_file(led_cdev->dev, &dev_attr_brightness);
178   - list_del(&led_cdev->node);
179   -err_out:
180   - device_unregister(led_cdev->dev);
181   - return rc;
182 159 }
  160 +
183 161 EXPORT_SYMBOL_GPL(led_classdev_register);
184 162  
185 163 /**
186 164  
... ... @@ -190,10 +168,7 @@
190 168 */
191 169 void led_classdev_unregister(struct led_classdev *led_cdev)
192 170 {
193   - device_remove_file(led_cdev->dev, &dev_attr_max_brightness);
194   - device_remove_file(led_cdev->dev, &dev_attr_brightness);
195 171 #ifdef CONFIG_LEDS_TRIGGERS
196   - device_remove_file(led_cdev->dev, &dev_attr_trigger);
197 172 down_write(&led_cdev->trigger_lock);
198 173 if (led_cdev->trigger)
199 174 led_trigger_set(led_cdev, NULL);
... ... @@ -215,6 +190,7 @@
215 190 return PTR_ERR(leds_class);
216 191 leds_class->suspend = led_suspend;
217 192 leds_class->resume = led_resume;
  193 + leds_class->dev_attrs = led_class_attrs;
218 194 return 0;
219 195 }
220 196