Skip to content

Commit 4dee060

Browse files
committed
Merge tag 'leds-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds
Pull LED updates from Pavel Machek: "Johannes pointed out that locking is still problematic with triggers list, attempt to solve that by using RCU" * tag 'leds-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds: leds: trigger: Disable CPU trigger on PREEMPT_RT leds: trigger: use RCU to protect the led_cdevs list led-class-flash: fix -Wrestrict warning
2 parents 73d21a3 + 97b31c1 commit 4dee060

File tree

4 files changed

+24
-22
lines changed

4 files changed

+24
-22
lines changed

drivers/leds/led-class-flash.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ static ssize_t flash_fault_show(struct device *dev,
207207
mask <<= 1;
208208
}
209209

210-
return sprintf(buf, "%s\n", buf);
210+
return strlen(strcat(buf, "\n"));
211211
}
212212
static DEVICE_ATTR_RO(flash_fault);
213213

drivers/leds/led-triggers.c

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ EXPORT_SYMBOL_GPL(led_trigger_read);
157157
/* Caller must ensure led_cdev->trigger_lock held */
158158
int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
159159
{
160-
unsigned long flags;
161160
char *event = NULL;
162161
char *envp[2];
163162
const char *name;
@@ -171,10 +170,13 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
171170

172171
/* Remove any existing trigger */
173172
if (led_cdev->trigger) {
174-
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
175-
list_del(&led_cdev->trig_list);
176-
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
177-
flags);
173+
spin_lock(&led_cdev->trigger->leddev_list_lock);
174+
list_del_rcu(&led_cdev->trig_list);
175+
spin_unlock(&led_cdev->trigger->leddev_list_lock);
176+
177+
/* ensure it's no longer visible on the led_cdevs list */
178+
synchronize_rcu();
179+
178180
cancel_work_sync(&led_cdev->set_brightness_work);
179181
led_stop_software_blink(led_cdev);
180182
if (led_cdev->trigger->deactivate)
@@ -186,9 +188,9 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
186188
led_set_brightness(led_cdev, LED_OFF);
187189
}
188190
if (trig) {
189-
write_lock_irqsave(&trig->leddev_list_lock, flags);
190-
list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
191-
write_unlock_irqrestore(&trig->leddev_list_lock, flags);
191+
spin_lock(&trig->leddev_list_lock);
192+
list_add_tail_rcu(&led_cdev->trig_list, &trig->led_cdevs);
193+
spin_unlock(&trig->leddev_list_lock);
192194
led_cdev->trigger = trig;
193195

194196
if (trig->activate)
@@ -223,9 +225,10 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
223225
trig->deactivate(led_cdev);
224226
err_activate:
225227

226-
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
227-
list_del(&led_cdev->trig_list);
228-
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
228+
spin_lock(&led_cdev->trigger->leddev_list_lock);
229+
list_del_rcu(&led_cdev->trig_list);
230+
spin_unlock(&led_cdev->trigger->leddev_list_lock);
231+
synchronize_rcu();
229232
led_cdev->trigger = NULL;
230233
led_cdev->trigger_data = NULL;
231234
led_set_brightness(led_cdev, LED_OFF);
@@ -285,7 +288,7 @@ int led_trigger_register(struct led_trigger *trig)
285288
struct led_classdev *led_cdev;
286289
struct led_trigger *_trig;
287290

288-
rwlock_init(&trig->leddev_list_lock);
291+
spin_lock_init(&trig->leddev_list_lock);
289292
INIT_LIST_HEAD(&trig->led_cdevs);
290293

291294
down_write(&triggers_list_lock);
@@ -378,15 +381,14 @@ void led_trigger_event(struct led_trigger *trig,
378381
enum led_brightness brightness)
379382
{
380383
struct led_classdev *led_cdev;
381-
unsigned long flags;
382384

383385
if (!trig)
384386
return;
385387

386-
read_lock_irqsave(&trig->leddev_list_lock, flags);
387-
list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
388+
rcu_read_lock();
389+
list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list)
388390
led_set_brightness(led_cdev, brightness);
389-
read_unlock_irqrestore(&trig->leddev_list_lock, flags);
391+
rcu_read_unlock();
390392
}
391393
EXPORT_SYMBOL_GPL(led_trigger_event);
392394

@@ -397,20 +399,19 @@ static void led_trigger_blink_setup(struct led_trigger *trig,
397399
int invert)
398400
{
399401
struct led_classdev *led_cdev;
400-
unsigned long flags;
401402

402403
if (!trig)
403404
return;
404405

405-
read_lock_irqsave(&trig->leddev_list_lock, flags);
406-
list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
406+
rcu_read_lock();
407+
list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) {
407408
if (oneshot)
408409
led_blink_set_oneshot(led_cdev, delay_on, delay_off,
409410
invert);
410411
else
411412
led_blink_set(led_cdev, delay_on, delay_off);
412413
}
413-
read_unlock_irqrestore(&trig->leddev_list_lock, flags);
414+
rcu_read_unlock();
414415
}
415416

416417
void led_trigger_blink(struct led_trigger *trig,

drivers/leds/trigger/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ config LEDS_TRIGGER_BACKLIGHT
6464

6565
config LEDS_TRIGGER_CPU
6666
bool "LED CPU Trigger"
67+
depends on !PREEMPT_RT
6768
help
6869
This allows LEDs to be controlled by active CPUs. This shows
6970
the active CPUs across an array of LEDs so you can see which

include/linux/leds.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ struct led_trigger {
360360
struct led_hw_trigger_type *trigger_type;
361361

362362
/* LEDs under control by this trigger (for simple triggers) */
363-
rwlock_t leddev_list_lock;
363+
spinlock_t leddev_list_lock;
364364
struct list_head led_cdevs;
365365

366366
/* Link to next registered trigger */

0 commit comments

Comments
 (0)