Commit 14b5d6dd40b3091cb5f566568baa4a74dc619286
Committed by
Richard Purdie
1 parent
0493a4ff10
Exists in
master
and in
7 other branches
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 |