Commit 4dee0606 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 73d21a35 97b31c1f
...@@ -207,7 +207,7 @@ static ssize_t flash_fault_show(struct device *dev, ...@@ -207,7 +207,7 @@ static ssize_t flash_fault_show(struct device *dev,
mask <<= 1; mask <<= 1;
} }
return sprintf(buf, "%s\n", buf); return strlen(strcat(buf, "\n"));
} }
static DEVICE_ATTR_RO(flash_fault); static DEVICE_ATTR_RO(flash_fault);
......
...@@ -157,7 +157,6 @@ EXPORT_SYMBOL_GPL(led_trigger_read); ...@@ -157,7 +157,6 @@ EXPORT_SYMBOL_GPL(led_trigger_read);
/* Caller must ensure led_cdev->trigger_lock held */ /* Caller must ensure led_cdev->trigger_lock held */
int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
{ {
unsigned long flags;
char *event = NULL; char *event = NULL;
char *envp[2]; char *envp[2];
const char *name; const char *name;
...@@ -171,10 +170,13 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) ...@@ -171,10 +170,13 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
/* Remove any existing trigger */ /* Remove any existing trigger */
if (led_cdev->trigger) { if (led_cdev->trigger) {
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); spin_lock(&led_cdev->trigger->leddev_list_lock);
list_del(&led_cdev->trig_list); list_del_rcu(&led_cdev->trig_list);
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, spin_unlock(&led_cdev->trigger->leddev_list_lock);
flags);
/* ensure it's no longer visible on the led_cdevs list */
synchronize_rcu();
cancel_work_sync(&led_cdev->set_brightness_work); cancel_work_sync(&led_cdev->set_brightness_work);
led_stop_software_blink(led_cdev); led_stop_software_blink(led_cdev);
if (led_cdev->trigger->deactivate) if (led_cdev->trigger->deactivate)
...@@ -186,9 +188,9 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) ...@@ -186,9 +188,9 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
led_set_brightness(led_cdev, LED_OFF); led_set_brightness(led_cdev, LED_OFF);
} }
if (trig) { if (trig) {
write_lock_irqsave(&trig->leddev_list_lock, flags); spin_lock(&trig->leddev_list_lock);
list_add_tail(&led_cdev->trig_list, &trig->led_cdevs); list_add_tail_rcu(&led_cdev->trig_list, &trig->led_cdevs);
write_unlock_irqrestore(&trig->leddev_list_lock, flags); spin_unlock(&trig->leddev_list_lock);
led_cdev->trigger = trig; led_cdev->trigger = trig;
if (trig->activate) if (trig->activate)
...@@ -223,9 +225,10 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig) ...@@ -223,9 +225,10 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
trig->deactivate(led_cdev); trig->deactivate(led_cdev);
err_activate: err_activate:
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); spin_lock(&led_cdev->trigger->leddev_list_lock);
list_del(&led_cdev->trig_list); list_del_rcu(&led_cdev->trig_list);
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags); spin_unlock(&led_cdev->trigger->leddev_list_lock);
synchronize_rcu();
led_cdev->trigger = NULL; led_cdev->trigger = NULL;
led_cdev->trigger_data = NULL; led_cdev->trigger_data = NULL;
led_set_brightness(led_cdev, LED_OFF); led_set_brightness(led_cdev, LED_OFF);
...@@ -285,7 +288,7 @@ int led_trigger_register(struct led_trigger *trig) ...@@ -285,7 +288,7 @@ int led_trigger_register(struct led_trigger *trig)
struct led_classdev *led_cdev; struct led_classdev *led_cdev;
struct led_trigger *_trig; struct led_trigger *_trig;
rwlock_init(&trig->leddev_list_lock); spin_lock_init(&trig->leddev_list_lock);
INIT_LIST_HEAD(&trig->led_cdevs); INIT_LIST_HEAD(&trig->led_cdevs);
down_write(&triggers_list_lock); down_write(&triggers_list_lock);
...@@ -378,15 +381,14 @@ void led_trigger_event(struct led_trigger *trig, ...@@ -378,15 +381,14 @@ void led_trigger_event(struct led_trigger *trig,
enum led_brightness brightness) enum led_brightness brightness)
{ {
struct led_classdev *led_cdev; struct led_classdev *led_cdev;
unsigned long flags;
if (!trig) if (!trig)
return; return;
read_lock_irqsave(&trig->leddev_list_lock, flags); rcu_read_lock();
list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list)
led_set_brightness(led_cdev, brightness); led_set_brightness(led_cdev, brightness);
read_unlock_irqrestore(&trig->leddev_list_lock, flags); rcu_read_unlock();
} }
EXPORT_SYMBOL_GPL(led_trigger_event); EXPORT_SYMBOL_GPL(led_trigger_event);
...@@ -397,20 +399,19 @@ static void led_trigger_blink_setup(struct led_trigger *trig, ...@@ -397,20 +399,19 @@ static void led_trigger_blink_setup(struct led_trigger *trig,
int invert) int invert)
{ {
struct led_classdev *led_cdev; struct led_classdev *led_cdev;
unsigned long flags;
if (!trig) if (!trig)
return; return;
read_lock_irqsave(&trig->leddev_list_lock, flags); rcu_read_lock();
list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) { list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) {
if (oneshot) if (oneshot)
led_blink_set_oneshot(led_cdev, delay_on, delay_off, led_blink_set_oneshot(led_cdev, delay_on, delay_off,
invert); invert);
else else
led_blink_set(led_cdev, delay_on, delay_off); led_blink_set(led_cdev, delay_on, delay_off);
} }
read_unlock_irqrestore(&trig->leddev_list_lock, flags); rcu_read_unlock();
} }
void led_trigger_blink(struct led_trigger *trig, void led_trigger_blink(struct led_trigger *trig,
......
...@@ -64,6 +64,7 @@ config LEDS_TRIGGER_BACKLIGHT ...@@ -64,6 +64,7 @@ config LEDS_TRIGGER_BACKLIGHT
config LEDS_TRIGGER_CPU config LEDS_TRIGGER_CPU
bool "LED CPU Trigger" bool "LED CPU Trigger"
depends on !PREEMPT_RT
help help
This allows LEDs to be controlled by active CPUs. This shows This allows LEDs to be controlled by active CPUs. This shows
the active CPUs across an array of LEDs so you can see which the active CPUs across an array of LEDs so you can see which
......
...@@ -360,7 +360,7 @@ struct led_trigger { ...@@ -360,7 +360,7 @@ struct led_trigger {
struct led_hw_trigger_type *trigger_type; struct led_hw_trigger_type *trigger_type;
/* LEDs under control by this trigger (for simple triggers) */ /* LEDs under control by this trigger (for simple triggers) */
rwlock_t leddev_list_lock; spinlock_t leddev_list_lock;
struct list_head led_cdevs; struct list_head led_cdevs;
/* Link to next registered trigger */ /* Link to next registered trigger */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment